Merge "Tidy up the "unbundled" provider API"
diff --git a/Android.bp b/Android.bp
index c6f9362..5953007 100644
--- a/Android.bp
+++ b/Android.bp
@@ -547,6 +547,7 @@
     exclude_srcs: ["core/java/android/content/pm/AndroidTestBaseUpdater.java"],
     aidl: {
         generate_get_transaction_name: true,
+        local_include_dirs: ["media/aidl"],
     },
     dxflags: [
         "--core-library",
@@ -583,6 +584,7 @@
         // in favor of an API stubs dependency in java_library "framework" below.
         "mimemap",
         "mediatranscoding_aidl_interface-java",
+        "soundtrigger_middleware-aidl-java",
     ],
     // For backwards compatibility.
     stem: "framework",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ca921ff..c82fee0f 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -83,6 +83,10 @@
     merge_annotations_dirs: [
         "metalava-manual",
     ],
+    // TODO(b/169090544): remove below aidl includes.
+    aidl: {
+        local_include_dirs: ["media/aidl"],
+    },
 }
 
 droidstubs {
@@ -150,6 +154,10 @@
         ":current-support-api",
         ":current-androidx-api",
     ],
+    // TODO(b/169090544): remove below aidl includes.
+    aidl: {
+        local_include_dirs: ["media/aidl"],
+    },
 }
 
 doc_defaults {
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index fc5efc6..7a8d1a1 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -11,6 +11,7 @@
                libs/input/
                services/core/jni/
                services/incremental/
+               tools/
 
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 0458e79..852fcc6 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -51,9 +51,12 @@
         ":android_icu4j_public_api_files",
         "**/package.html",
     ],
-    // TODO(b/147699819): remove below aidl includes.
+    // TODO(b/147699819, b/169090544): remove below aidl includes.
     aidl: {
-        local_include_dirs: ["telephony/java"],
+        local_include_dirs: [
+            "telephony/java",
+            "media/aidl",
+        ],
     },
     libs: ["framework-internal-utils"],
     installable: false,
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
index d97b500..54e1860 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
@@ -16,19 +16,23 @@
 
 package android.view.autofill;
 
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
 import static org.junit.Assert.assertTrue;
 
 import android.os.Looper;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.PerfTestActivity;
-import android.perftests.utils.SettingsHelper;
 import android.perftests.utils.SettingsStateKeeperRule;
 import android.provider.Settings;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.rules.RuleChain;
@@ -38,6 +42,8 @@
  */
 public abstract class AbstractAutofillPerfTestCase {
 
+    private static final String TAG = "AbstractAutofillPerfTestCase";
+
     @ClassRule
     public static final SettingsStateKeeperRule mServiceSettingsKeeper =
             new SettingsStateKeeperRule(InstrumentationRegistry.getTargetContext(),
@@ -60,6 +66,27 @@
         mLayoutId = layoutId;
     }
 
+    @BeforeClass
+    public static void disableDefaultAugmentedService() {
+        Log.v(TAG, "@BeforeClass: disableDefaultAugmentedService()");
+        setDefaultAugmentedAutofillServiceEnabled(false);
+    }
+
+    @AfterClass
+    public static void enableDefaultAugmentedService() {
+        Log.v(TAG, "@AfterClass: enableDefaultAugmentedService()");
+        setDefaultAugmentedAutofillServiceEnabled(true);
+    }
+
+    /**
+     * Enables / disables the default augmented autofill service.
+     */
+    private static void setDefaultAugmentedAutofillServiceEnabled(boolean enabled) {
+        Log.d(TAG, "setDefaultAugmentedAutofillServiceEnabled(): " + enabled);
+        runShellCommand("cmd autofill set default-augmented-service-enabled 0 %s",
+                Boolean.toString(enabled));
+    }
+
     /**
      * Prepares the activity so that by the time the test is run it has reference to its fields.
      */
@@ -80,23 +107,4 @@
      * Initializes the {@link PerfTestActivity} after it was launched.
      */
     protected abstract void onCreate(PerfTestActivity activity);
-
-    /**
-     * Uses the {@code settings} binary to set the autofill service.
-     */
-    protected void setService() {
-        SettingsHelper.syncSet(InstrumentationRegistry.getTargetContext(),
-                SettingsHelper.NAMESPACE_SECURE,
-                Settings.Secure.AUTOFILL_SERVICE,
-                MyAutofillService.COMPONENT_NAME);
-    }
-
-    /**
-     * Uses the {@code settings} binary to reset the autofill service.
-     */
-    protected void resetService() {
-        SettingsHelper.syncDelete(InstrumentationRegistry.getTargetContext(),
-                SettingsHelper.NAMESPACE_SECURE,
-                Settings.Secure.AUTOFILL_SERVICE);
-    }
 }
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
index f1f812d..2475d98 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
@@ -18,10 +18,13 @@
 
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
+import android.perftests.utils.SettingsHelper;
+import android.provider.Settings;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
@@ -44,19 +47,26 @@
     @Override
     protected void starting(Description description) {
         super.starting(description);
+        final String testName = description.getDisplayName();
+        Log.i(TAG, "Starting " + testName);
 
         enableVerboseLog();
-        MyAutofillService.resetStaticState();
-        MyAutofillService.setEnabled(true);
+        // Prepare the service before each test.
+        // Disable the current AutofillService.
+        resetAutofillService();
+        // Set MyAutofillService status enable, it can start to accept the calls.
+        enableMyAutofillService();
         setServiceWatcher();
     }
 
     @Override
     protected void finished(Description description) {
         super.finished(description);
-
+        final String testName = description.getDisplayName();
+        Log.i(TAG, "Finished " + testName);
         restoreLogLevel();
-        disableService();
+        // Set MyAutofillService status disable, so the calls are ignored.
+        disableMyAutofillService();
         clearServiceWatcher();
     }
 
@@ -67,12 +77,31 @@
         }
     }
 
-    private void enableService() {
+    /**
+     * Uses the {@code settings} binary to set the autofill service.
+     */
+    void setAutofillService() {
+        SettingsHelper.syncSet(InstrumentationRegistry.getTargetContext(),
+                SettingsHelper.NAMESPACE_SECURE,
+                Settings.Secure.AUTOFILL_SERVICE,
+                MyAutofillService.COMPONENT_NAME);
+    }
+
+    /**
+     * Uses the {@code settings} binary to reset the autofill service.
+     */
+    void resetAutofillService() {
+        SettingsHelper.syncDelete(InstrumentationRegistry.getTargetContext(),
+                SettingsHelper.NAMESPACE_SECURE,
+                Settings.Secure.AUTOFILL_SERVICE);
+    }
+
+    private void enableMyAutofillService() {
         MyAutofillService.resetStaticState();
         MyAutofillService.setEnabled(true);
     }
 
-    private void disableService() {
+    private void disableMyAutofillService() {
         // Must disable service so calls are ignored in case of errors during the test case;
         // otherwise, other tests will fail because these calls are made in the UI thread (as both
         // the service, the tests, and the app run in the same process).
@@ -88,7 +117,7 @@
     }
 
     private void restoreLogLevel() {
-        Log.w(TAG, "restoreLogLevel to " + mOriginalLogLevel);
+        Log.d(TAG, "restoreLogLevel to " + mOriginalLogLevel);
         if (!mOriginalLogLevel.equals("verbose")) {
             runShellCommand("cmd autofill set log_level %s", mOriginalLogLevel);
         }
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
index 99b2590..37b4bde 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -55,7 +55,7 @@
      */
     @Test
     public void testFocus_noService() throws Throwable {
-        resetService();
+        mTestWatcher.resetAutofillService();
 
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
@@ -73,7 +73,7 @@
     @Test
     public void testFocus_serviceDoesNotAutofill() throws Throwable {
         MyAutofillService.newCannedResponse().reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Must first focus in a field to trigger autofill and wait for service response
         // outside the loop
@@ -102,7 +102,7 @@
                 .setUsername(mUsername.getAutofillId(), "user")
                 .setPassword(mPassword.getAutofillId(), "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Callback is used to slow down the calls made to the autofill server so the
         // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
@@ -157,7 +157,7 @@
                 .setUsername(mUsername.getAutofillId(), "user")
                 .setIgnored(mPassword.getAutofillId())
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         // Callback is used to slow down the calls made to the autofill server so the
         // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
@@ -201,7 +201,7 @@
      */
     @Test
     public void testChange_noService() throws Throwable {
-        resetService();
+        mTestWatcher.resetAutofillService();
 
         changeTest(false);
     }
@@ -213,7 +213,7 @@
     @Test
     public void testChange_serviceDoesNotAutofill() throws Throwable {
         MyAutofillService.newCannedResponse().reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -227,7 +227,7 @@
                 .setUsername(mUsername.getAutofillId(), "user")
                 .setPassword(mPassword.getAutofillId(), "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -242,7 +242,7 @@
                 .setUsername(mUsername.getAutofillId(), "user")
                 .setIgnored(mPassword.getAutofillId())
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         changeTest(true);
     }
@@ -274,7 +274,7 @@
                 .setUsername(mUsername.getAutofillId(), "user")
                 .setPassword(mPassword.getAutofillId(), "pass")
                 .reply();
-        setService();
+        mTestWatcher.setAutofillService();
 
         MyAutofillCallback callback = new MyAutofillCallback();
         mAfm.registerCallback(callback);
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
index 77c1b85..ddac68b 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
@@ -126,6 +126,7 @@
             onError("ignoring onFillRequest(): response not set", callback);
             return;
         }
+        // TODO(b/162216576): fix error FillResponse
         Dataset.Builder dataset = new Dataset.Builder(newDatasetPresentation("dataset"));
         boolean hasData = false;
         if (response.mUsername != null) {
diff --git a/api/Android.bp b/api/Android.bp
index 54031da..490c980 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -43,3 +43,58 @@
     cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)",
     visibility: ["//visibility:public"],
 }
+
+genrule {
+    name: "frameworks-base-api-current-merged.txt",
+    srcs: [
+        ":conscrypt.module.public.api{.public.api.txt}",
+        ":framework-graphics{.public.api.txt}",
+        ":framework-media{.public.api.txt}",
+        ":framework-mediaprovider{.public.api.txt}",
+        ":framework-permission{.public.api.txt}",
+        ":framework-sdkextensions{.public.api.txt}",
+        ":framework-statsd{.public.api.txt}",
+        ":framework-tethering{.public.api.txt}",
+        ":framework-wifi{.public.api.txt}",
+        ":non-updatable-current.txt",
+    ],
+    out: ["current.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+    name: "frameworks-base-api-system-current-merged.txt",
+    srcs: [
+        ":framework-graphics{.system.api.txt}",
+        ":framework-media{.system.api.txt}",
+        ":framework-mediaprovider{.system.api.txt}",
+        ":framework-permission{.system.api.txt}",
+        ":framework-sdkextensions{.system.api.txt}",
+        ":framework-statsd{.system.api.txt}",
+        ":framework-tethering{.system.api.txt}",
+        ":framework-wifi{.system.api.txt}",
+        ":non-updatable-system-current.txt",
+    ],
+    out: ["system-current.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+    name: "frameworks-base-api-module-lib-current-merged.txt",
+    srcs: [
+        ":framework-graphics{.module-lib.api.txt}",
+        ":framework-media{.module-lib.api.txt}",
+        ":framework-mediaprovider{.module-lib.api.txt}",
+        ":framework-permission{.module-lib.api.txt}",
+        ":framework-sdkextensions{.module-lib.api.txt}",
+        ":framework-statsd{.module-lib.api.txt}",
+        ":framework-tethering{.module-lib.api.txt}",
+        ":framework-wifi{.module-lib.api.txt}",
+        ":non-updatable-module-lib-current.txt",
+    ],
+    out: ["module-lib-current.txt"],
+    tools: ["metalava"],
+    cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
diff --git a/api/current.txt b/api/current.txt
index f7bcce7..4b0901a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14292,6 +14292,7 @@
 
   public final class BlurShader extends android.graphics.Shader {
     ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+    ctor public BlurShader(float, float, @Nullable android.graphics.Shader, @NonNull android.graphics.Shader.TileMode);
   }
 
   public class Camera {
@@ -15644,6 +15645,7 @@
 
   public enum Shader.TileMode {
     enum_constant public static final android.graphics.Shader.TileMode CLAMP;
+    enum_constant public static final android.graphics.Shader.TileMode DECAL;
     enum_constant public static final android.graphics.Shader.TileMode MIRROR;
     enum_constant public static final android.graphics.Shader.TileMode REPEAT;
   }
@@ -16387,7 +16389,9 @@
     method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
     method @NonNull public java.nio.ByteBuffer getBuffer();
     method @Nullable public java.io.File getFile();
+    method public float getGlyphBounds(@IntRange(from=0) int, @NonNull android.graphics.Paint, @Nullable android.graphics.RectF);
     method @NonNull public android.os.LocaleList getLocaleList();
+    method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
     method @NonNull public android.graphics.fonts.FontStyle getStyle();
     method @IntRange(from=0) public int getTtcIndex();
   }
@@ -16399,6 +16403,7 @@
     ctor public Font.Builder(@NonNull android.os.ParcelFileDescriptor, @IntRange(from=0) long, @IntRange(from=0xffffffff) long);
     ctor public Font.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
     ctor public Font.Builder(@NonNull android.content.res.Resources, int);
+    ctor public Font.Builder(@NonNull android.graphics.fonts.Font);
     method @NonNull public android.graphics.fonts.Font build() throws java.io.IOException;
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable String);
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
@@ -24927,6 +24932,10 @@
     method public double getAttributeDouble(@NonNull String, double);
     method public int getAttributeInt(@NonNull String, int);
     method @Nullable public long[] getAttributeRange(@NonNull String);
+    method public long getDateTime();
+    method public long getDateTimeDigitized();
+    method public long getDateTimeOriginal();
+    method public long getGpsDateTime();
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
     method public android.graphics.Bitmap getThumbnailBitmap();
@@ -26297,6 +26306,7 @@
     field public static final String KEY_ROTATION = "rotation-degrees";
     field public static final String KEY_SAMPLE_RATE = "sample-rate";
     field public static final String KEY_SLICE_HEIGHT = "slice-height";
+    field public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
     field public static final String KEY_STRIDE = "stride";
     field public static final String KEY_TEMPORAL_LAYERING = "ts-schema";
     field public static final String KEY_TILE_HEIGHT = "tile-height";
@@ -32023,9 +32033,15 @@
     method public int describeContents();
     method public String getFqdn();
     method public String getFriendlyName();
+    method @Nullable public long[] getMatchAllOis();
+    method @Nullable public long[] getMatchAnyOis();
+    method @Nullable public String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(String);
     method public void setFriendlyName(String);
+    method public void setMatchAllOis(@Nullable long[]);
+    method public void setMatchAnyOis(@Nullable long[]);
+    method public void setOtherHomePartners(@Nullable String[]);
     method public void setRoamingConsortiumOis(long[]);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index c4f9067..118184d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4399,6 +4399,8 @@
   }
 
   public static final class MediaTranscodeManager.TranscodingRequest {
+    method public int getClientPid();
+    method public int getClientUid();
     method @NonNull public android.net.Uri getDestinationUri();
     method public int getPriority();
     method @NonNull public android.net.Uri getSourceUri();
@@ -4409,6 +4411,8 @@
   public static final class MediaTranscodeManager.TranscodingRequest.Builder {
     ctor public MediaTranscodeManager.TranscodingRequest.Builder();
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
@@ -7424,7 +7428,7 @@
     field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
-    field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+    field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
     field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/api/test-current.txt b/api/test-current.txt
index 5082c57..de67f40 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -537,7 +537,8 @@
 
   public final class UiAutomation {
     method public void destroy();
-    method public android.os.ParcelFileDescriptor[] executeShellCommandRw(String);
+    method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRw(@NonNull String);
+    method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String);
     method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
     method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
     method public void syncInputTransactions();
@@ -997,6 +998,7 @@
     method public void setEnableRollback(boolean, int);
     method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+    method public void setInstallAsInstantApp(boolean);
     method public void setInstallerPackageName(@Nullable String);
     method public void setRequestDowngrade(boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
@@ -1852,6 +1854,8 @@
   }
 
   public static final class MediaTranscodeManager.TranscodingRequest {
+    method public int getClientPid();
+    method public int getClientUid();
     method @NonNull public android.net.Uri getDestinationUri();
     method public int getPriority();
     method @NonNull public android.net.Uri getSourceUri();
@@ -1862,6 +1866,8 @@
   public static final class MediaTranscodeManager.TranscodingRequest.Builder {
     ctor public MediaTranscodeManager.TranscodingRequest.Builder();
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
diff --git a/cmds/statsd/src/condition/ConditionTimer.h b/cmds/statsd/src/condition/ConditionTimer.h
index 442bc11..1fbe252 100644
--- a/cmds/statsd/src/condition/ConditionTimer.h
+++ b/cmds/statsd/src/condition/ConditionTimer.h
@@ -36,7 +36,7 @@
 public:
     explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
         if (initCondition) {
-            mLastConditionTrueTimestampNs = bucketStartNs;
+            mLastConditionChangeTimestampNs = bucketStartNs;
         }
     };
 
@@ -44,21 +44,46 @@
     // When a new bucket is created, this value will be reset to 0.
     int64_t mTimerNs = 0;
 
-    // Last elapsed real timestamp when condition turned to true
-    // When a new bucket is created and the condition is true, then the timestamp is set
-    // to be the bucket start timestamp.
-    int64_t mLastConditionTrueTimestampNs = 0;
+    // Last elapsed real timestamp when condition changed.
+    int64_t mLastConditionChangeTimestampNs = 0;
 
     bool mCondition = false;
 
     int64_t newBucketStart(int64_t nextBucketStartNs) {
         if (mCondition) {
-            mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
-            mLastConditionTrueTimestampNs = nextBucketStartNs;
+            // Normally, the next bucket happens after the last condition
+            // change. In this case, add the time between the condition becoming
+            // true to the next bucket start time.
+            // Otherwise, the next bucket start time is before the last
+            // condition change time, this means that the condition was false at
+            // the bucket boundary before the condition became true, so the
+            // timer should not get updated and the last condition change time
+            // remains as is.
+            if (nextBucketStartNs >= mLastConditionChangeTimestampNs) {
+                mTimerNs += (nextBucketStartNs - mLastConditionChangeTimestampNs);
+                mLastConditionChangeTimestampNs = nextBucketStartNs;
+            }
+        } else if (mLastConditionChangeTimestampNs > nextBucketStartNs) {
+            // The next bucket start time is before the last condition change
+            // time, this means that the condition was true at the bucket
+            // boundary before the condition became false, so adjust the timer
+            // to match how long the condition was true to the bucket boundary.
+            // This means remove the amount the condition stayed true in the
+            // next bucket from the current bucket.
+            mTimerNs -= (mLastConditionChangeTimestampNs - nextBucketStartNs);
         }
 
         int64_t temp = mTimerNs;
         mTimerNs = 0;
+
+        if (!mCondition && (mLastConditionChangeTimestampNs > nextBucketStartNs)) {
+            // The next bucket start time is before the last condition change
+            // time, this means that the condition was true at the bucket
+            // boundary and remained true in the next bucket up to the condition
+            // change to false, so adjust the timer to match how long the
+            // condition stayed true in the next bucket (now the current bucket).
+            mTimerNs = mLastConditionChangeTimestampNs - nextBucketStartNs;
+        }
         return temp;
     }
 
@@ -67,11 +92,10 @@
             return;
         }
         mCondition = newCondition;
-        if (newCondition) {
-            mLastConditionTrueTimestampNs = timestampNs;
-        } else {
-            mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
+        if (newCondition == false) {
+            mTimerNs += (timestampNs - mLastConditionChangeTimestampNs);
         }
+        mLastConditionChangeTimestampNs = timestampNs;
     }
 
     FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
@@ -80,4 +104,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 39ae9a4..3d57cfe 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -301,7 +301,6 @@
             protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
             protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME,
                                (long long)(NanoToMillis(dropEvent.dropTimeNs)));
-            ;
             protoOutput->end(dropEventToken);
         }
         protoOutput->end(wrapperToken);
@@ -346,8 +345,11 @@
                 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
                                    (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
             }
-            // only write the condition timer value if the metric has a condition.
-            if (mConditionTrackerIndex >= 0) {
+            // We only write the condition timer value if the metric has a
+            // condition and/or is sliced by state.
+            // If the metric is sliced by state, the condition timer value is
+            // also sliced by state to reflect time spent in that state.
+            if (mConditionTrackerIndex >= 0 || !mSlicedStateAtoms.empty()) {
                 protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
                                    (long long)bucket.mConditionTrueNs);
             }
@@ -454,6 +456,8 @@
 
     // Let condition timer know of new active state.
     mConditionTimer.onConditionChanged(mIsActive, eventTimeNs);
+
+    updateCurrentSlicedBucketConditionTimers(mIsActive, eventTimeNs);
 }
 
 void ValueMetricProducer::onConditionChangedLocked(const bool condition,
@@ -476,6 +480,8 @@
         invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
         mCondition = ConditionState::kUnknown;
         mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+
+        updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
         return;
     }
 
@@ -517,6 +523,29 @@
 
     flushIfNeededLocked(eventTimeNs);
     mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+
+    updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
+}
+
+void ValueMetricProducer::updateCurrentSlicedBucketConditionTimers(bool newCondition,
+                                                                   int64_t eventTimeNs) {
+    if (mSlicedStateAtoms.empty()) {
+        return;
+    }
+
+    // Utilize the current state key of each DimensionsInWhat key to determine
+    // which condition timers to update.
+    //
+    // Assumes that the MetricDimensionKey exists in `mCurrentSlicedBucket`.
+    bool inPulledData;
+    for (const auto& [dimensionInWhatKey, dimensionInWhatInfo] : mCurrentBaseInfo) {
+        // If the new condition is true, turn ON the condition timer only if
+        // the DimensionInWhat key was present in the pulled data.
+        inPulledData = dimensionInWhatInfo.hasCurrentState;
+        mCurrentSlicedBucket[MetricDimensionKey(dimensionInWhatKey,
+                                                dimensionInWhatInfo.currentState)]
+                .conditionTimer.onConditionChanged(newCondition && inPulledData, eventTimeNs);
+    }
 }
 
 void ValueMetricProducer::prepareFirstBucketLocked() {
@@ -618,8 +647,8 @@
     // 2. A superset of the current mStateChangePrimaryKey
     // was not found in the new pulled data (i.e. not in mMatchedDimensionInWhatKeys)
     // then we need to reset the base.
-    for (auto& slice : mCurrentSlicedBucket) {
-        const auto& whatKey = slice.first.getDimensionKeyInWhat();
+    for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+        const auto& whatKey = metricDimensionKey.getDimensionKeyInWhat();
         bool presentInPulledData =
                 mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
         if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
@@ -627,6 +656,12 @@
             for (auto& baseInfo : it->second.baseInfos) {
                 baseInfo.hasBase = false;
             }
+            // Set to false when DimensionInWhat key is not present in a pull.
+            // Used in onMatchedLogEventInternalLocked() to ensure the condition
+            // timer is turned on the next pull when data is present.
+            it->second.hasCurrentState = false;
+            // Turn OFF condition timer for keys not present in pulled data.
+            currentValueBucket.conditionTimer.onConditionChanged(false, eventElapsedTimeNs);
         }
     }
     mMatchedMetricDimensionKeys.clear();
@@ -789,21 +824,26 @@
         return;
     }
 
-    DimensionsInWhatInfo& dimensionsInWhatInfo = mCurrentBaseInfo[whatKey];
+    const auto& returnVal =
+            mCurrentBaseInfo.emplace(whatKey, DimensionsInWhatInfo(getUnknownStateKey()));
+    DimensionsInWhatInfo& dimensionsInWhatInfo = returnVal.first->second;
+    const HashableDimensionKey oldStateKey = dimensionsInWhatInfo.currentState;
     vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos;
     if (baseInfos.size() < mFieldMatchers.size()) {
         VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
         baseInfos.resize(mFieldMatchers.size());
     }
 
+    // Ensure we turn on the condition timer in the case where dimensions
+    // were missing on a previous pull due to a state change.
+    bool stateChange = oldStateKey != stateKey;
     if (!dimensionsInWhatInfo.hasCurrentState) {
-        dimensionsInWhatInfo.currentState = getUnknownStateKey();
+        stateChange = true;
         dimensionsInWhatInfo.hasCurrentState = true;
     }
 
     // We need to get the intervals stored with the previous state key so we can
     // close these value intervals.
-    const auto oldStateKey = dimensionsInWhatInfo.currentState;
     vector<Interval>& intervals =
             mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals;
     if (intervals.size() < mFieldMatchers.size()) {
@@ -916,6 +956,17 @@
         interval.sampleSize += 1;
     }
 
+    // State change.
+    if (!mSlicedStateAtoms.empty() && stateChange) {
+        // Turn OFF the condition timer for the previous state key.
+        mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)]
+                .conditionTimer.onConditionChanged(false, eventTimeNs);
+
+        // Turn ON the condition timer for the new state key.
+        mCurrentSlicedBucket[MetricDimensionKey(whatKey, stateKey)]
+                .conditionTimer.onConditionChanged(true, eventTimeNs);
+    }
+
     // Only trigger the tracker if all intervals are correct and we have not skipped the bucket due
     // to MULTIPLE_BUCKETS_SKIPPED.
     if (useAnomalyDetection && !multipleBucketsSkipped(calcBucketsForwardCount(eventTimeNs))) {
@@ -990,12 +1041,18 @@
     if (!mCurrentBucketIsSkipped) {
         bool bucketHasData = false;
         // The current bucket is large enough to keep.
-        for (const auto& slice : mCurrentSlicedBucket) {
-            PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals);
-            bucket.mConditionTrueNs = conditionTrueDuration;
+        for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+            PastValueBucket bucket =
+                    buildPartialBucket(bucketEndTime, currentValueBucket.intervals);
+            if (!mSlicedStateAtoms.empty()) {
+                bucket.mConditionTrueNs =
+                        currentValueBucket.conditionTimer.newBucketStart(bucketEndTime);
+            } else {
+                bucket.mConditionTrueNs = conditionTrueDuration;
+            }
             // it will auto create new vector of ValuebucketInfo if the key is not found.
             if (bucket.valueIndex.size() > 0) {
-                auto& bucketList = mPastBuckets[slice.first];
+                auto& bucketList = mPastBuckets[metricDimensionKey];
                 bucketList.push_back(bucket);
                 bucketHasData = true;
             }
@@ -1023,11 +1080,18 @@
                 buildDropEvent(eventTimeNs, BucketDropReason::NO_DATA));
         mSkippedBuckets.emplace_back(bucketInGap);
     }
-
     appendToFullBucket(eventTimeNs > fullBucketEndTimeNs);
     initCurrentSlicedBucket(nextBucketStartTimeNs);
     // Update the condition timer again, in case we skipped buckets.
     mConditionTimer.newBucketStart(nextBucketStartTimeNs);
+
+    // NOTE: Update the condition timers in `mCurrentSlicedBucket` only when slicing
+    // by state. Otherwise, the "global" condition timer will be used.
+    if (!mSlicedStateAtoms.empty()) {
+        for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+            currentValueBucket.conditionTimer.newBucketStart(nextBucketStartTimeNs);
+        }
+    }
     mCurrentBucketNum += numBucketsForward;
 }
 
@@ -1069,6 +1133,17 @@
             interval.seenNewData = false;
         }
 
+        if (obsolete && !mSlicedStateAtoms.empty()) {
+            // When slicing by state, only delete the MetricDimensionKey when the
+            // state key in the MetricDimensionKey is not the current state key.
+            const HashableDimensionKey& dimensionInWhatKey = it->first.getDimensionKeyInWhat();
+            const auto& currentBaseInfoItr = mCurrentBaseInfo.find(dimensionInWhatKey);
+
+            if ((currentBaseInfoItr != mCurrentBaseInfo.end()) &&
+                (it->first.getStateValuesKey() == currentBaseInfoItr->second.currentState)) {
+                obsolete = false;
+            }
+        }
         if (obsolete) {
             it = mCurrentSlicedBucket.erase(it);
         } else {
@@ -1104,7 +1179,7 @@
         // Accumulate partial buckets with current value and then send to anomaly tracker.
         if (mCurrentFullBucket.size() > 0) {
             for (const auto& slice : mCurrentSlicedBucket) {
-                if (hitFullBucketGuardRailLocked(slice.first)) {
+                if (hitFullBucketGuardRailLocked(slice.first) || slice.second.intervals.empty()) {
                     continue;
                 }
                 // TODO: fix this when anomaly can accept double values
@@ -1125,7 +1200,7 @@
             // Skip aggregating the partial buckets since there's no previous partial bucket.
             for (const auto& slice : mCurrentSlicedBucket) {
                 for (auto& tracker : mAnomalyTrackers) {
-                    if (tracker != nullptr) {
+                    if (tracker != nullptr && !slice.second.intervals.empty()) {
                         // TODO: fix this when anomaly can accept double values
                         auto& interval = slice.second.intervals[0];
                         if (interval.hasValue) {
@@ -1139,10 +1214,12 @@
     } else {
         // Accumulate partial bucket.
         for (const auto& slice : mCurrentSlicedBucket) {
-            // TODO: fix this when anomaly can accept double values
-            auto& interval = slice.second.intervals[0];
-            if (interval.hasValue) {
-                mCurrentFullBucket[slice.first] += interval.value.long_value;
+            if (!slice.second.intervals.empty()) {
+                // TODO: fix this when anomaly can accept double values
+                auto& interval = slice.second.intervals[0];
+                if (interval.hasValue) {
+                    mCurrentFullBucket[slice.first] += interval.value.long_value;
+                }
             }
         }
     }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4b2599b..67de214 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -193,8 +193,14 @@
 
     // Internal state of an ongoing aggregation bucket.
     typedef struct CurrentValueBucket {
+        // If the `MetricDimensionKey` state key is the current state key, then
+        // the condition timer will be updated later (e.g. condition/state/active
+        // state change) with the correct condition and time.
+        CurrentValueBucket() : intervals(), conditionTimer(ConditionTimer(false, 0)) {}
         // Value information for each value field of the metric.
         std::vector<Interval> intervals;
+        // Tracks how long the condition is true.
+        ConditionTimer conditionTimer;
     } CurrentValueBucket;
 
     // Holds base information for diffing values from one value field.
@@ -206,7 +212,10 @@
     } BaseInfo;
 
     // State key and base information for a specific DimensionsInWhat key.
-    typedef struct {
+    typedef struct DimensionsInWhatInfo {
+        DimensionsInWhatInfo(const HashableDimensionKey& stateKey)
+            : baseInfos(), currentState(stateKey), hasCurrentState(false) {
+        }
         std::vector<BaseInfo> baseInfos;
         // Last seen state value(s).
         HashableDimensionKey currentState;
@@ -252,6 +261,10 @@
     // Reset diff base and mHasGlobalBase
     void resetBase();
 
+    // Updates the condition timers in the current sliced bucket when there is a
+    // condition change or an active state change.
+    void updateCurrentSlicedBucketConditionTimers(bool newCondition, int64_t eventTimeNs);
+
     static const size_t kBucketSize = sizeof(PastValueBucket{});
 
     const size_t mDimensionSoftLimit;
@@ -337,6 +350,11 @@
     FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
+    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions);
+    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange);
+    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange);
+    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket);
+    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary);
 
     FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed);
     FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed);
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 5dbf16d..2ae5763 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -24,6 +24,8 @@
 #include "matchers/EventMatcherWizard.h"
 #include "metrics_manager_util.h"
 
+using google::protobuf::MessageLite;
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -419,16 +421,19 @@
     return false;
 }
 
-bool determineEventMetricUpdateStatus(const StatsdConfig& config, const EventMetric& metric,
-                                      const unordered_map<int64_t, int>& oldMetricProducerMap,
-                                      const vector<sp<MetricProducer>>& oldMetricProducers,
-                                      const unordered_map<int64_t, int>& metricToActivationMap,
-                                      const set<int64_t>& replacedMatchers,
-                                      const set<int64_t>& replacedConditions,
-                                      UpdateStatus& updateStatus) {
-    int64_t id = metric.id();
+bool determineMetricUpdateStatus(
+        const StatsdConfig& config, const MessageLite& metric, const int64_t metricId,
+        const MetricType metricType, const set<int64_t>& matcherDependencies,
+        const set<int64_t>& conditionDependencies,
+        const ::google::protobuf::RepeatedField<int64_t>& stateDependencies,
+        const ::google::protobuf::RepeatedPtrField<MetricConditionLink>& conditionLinks,
+        const unordered_map<int64_t, int>& oldMetricProducerMap,
+        const vector<sp<MetricProducer>>& oldMetricProducers,
+        const unordered_map<int64_t, int>& metricToActivationMap,
+        const set<int64_t>& replacedMatchers, const set<int64_t>& replacedConditions,
+        const set<int64_t>& replacedStates, UpdateStatus& updateStatus) {
     // Check if new metric
-    const auto& oldMetricProducerIt = oldMetricProducerMap.find(id);
+    const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId);
     if (oldMetricProducerIt == oldMetricProducerMap.end()) {
         updateStatus = UPDATE_NEW;
         return true;
@@ -436,44 +441,85 @@
 
     // This is an existing metric, check if it has changed.
     uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, id, metricToActivationMap, metricHash)) {
+    if (!getMetricProtoHash(config, metric, metricId, metricToActivationMap, metricHash)) {
         return false;
     }
     const sp<MetricProducer> oldMetricProducer = oldMetricProducers[oldMetricProducerIt->second];
-    if (oldMetricProducer->getMetricType() != METRIC_TYPE_EVENT ||
+    if (oldMetricProducer->getMetricType() != metricType ||
         oldMetricProducer->getProtoHash() != metricHash) {
         updateStatus = UPDATE_REPLACE;
         return true;
     }
 
-    // Metric type and definition are the same. Need to check dependencies to see if they changed.
-    if (replacedMatchers.find(metric.what()) != replacedMatchers.end()) {
+    // Take intersections of the matchers/predicates/states that the metric
+    // depends on with those that have been replaced. If a metric depends on any
+    // replaced component, it too must be replaced.
+    set<int64_t> intersection;
+    set_intersection(matcherDependencies.begin(), matcherDependencies.end(),
+                     replacedMatchers.begin(), replacedMatchers.end(),
+                     inserter(intersection, intersection.begin()));
+    if (intersection.size() > 0) {
+        updateStatus = UPDATE_REPLACE;
+        return true;
+    }
+    set_intersection(conditionDependencies.begin(), conditionDependencies.end(),
+                     replacedConditions.begin(), replacedConditions.end(),
+                     inserter(intersection, intersection.begin()));
+    if (intersection.size() > 0) {
+        updateStatus = UPDATE_REPLACE;
+        return true;
+    }
+    set_intersection(stateDependencies.begin(), stateDependencies.end(), replacedStates.begin(),
+                     replacedStates.end(), inserter(intersection, intersection.begin()));
+    if (intersection.size() > 0) {
         updateStatus = UPDATE_REPLACE;
         return true;
     }
 
-    if (metric.has_condition()) {
-        if (replacedConditions.find(metric.condition()) != replacedConditions.end()) {
-            updateStatus = UPDATE_REPLACE;
-            return true;
-        }
-    }
-
-    if (metricActivationDepsChange(config, metricToActivationMap, id, replacedMatchers)) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    for (const auto& metricConditionLink : metric.links()) {
+    for (const auto& metricConditionLink : conditionLinks) {
         if (replacedConditions.find(metricConditionLink.condition()) != replacedConditions.end()) {
             updateStatus = UPDATE_REPLACE;
             return true;
         }
     }
+
+    if (metricActivationDepsChange(config, metricToActivationMap, metricId, replacedMatchers)) {
+        updateStatus = UPDATE_REPLACE;
+        return true;
+    }
+
     updateStatus = UPDATE_PRESERVE;
     return true;
 }
 
+bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
+                                      const unordered_map<int64_t, int>& oldMetricProducerMap,
+                                      const vector<sp<MetricProducer>>& oldMetricProducers,
+                                      const unordered_map<int64_t, int>& metricToActivationMap,
+                                      const set<int64_t>& replacedMatchers,
+                                      const set<int64_t>& replacedConditions,
+                                      const set<int64_t>& replacedStates,
+                                      vector<UpdateStatus>& metricsToUpdate) {
+    int metricIndex = 0;
+    for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
+        const EventMetric& metric = config.event_metric(i);
+        set<int64_t> conditionDependencies;
+        if (metric.has_condition()) {
+            conditionDependencies.insert(metric.condition());
+        }
+        if (!determineMetricUpdateStatus(
+                    config, metric, metric.id(), METRIC_TYPE_EVENT, {metric.what()},
+                    conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(),
+                    metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+                    replacedMatchers, replacedConditions, replacedStates,
+                    metricsToUpdate[metricIndex])) {
+            return false;
+        }
+    }
+    // TODO: determine update status for count, gauge, value, duration metrics.
+    return true;
+}
+
 bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
                    const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
                    const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
@@ -518,22 +564,16 @@
     }
 
     vector<UpdateStatus> metricsToUpdate(allMetricsCount, UPDATE_UNKNOWN);
+    if (!determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+                                          metricToActivationMap, replacedMatchers,
+                                          replacedConditions, replacedStates, metricsToUpdate)) {
+        return false;
+    }
+
+    // Now, perform the update. Must iterate the metric types in the same order
     int metricIndex = 0;
     for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
         newMetricProducerMap[config.event_metric(i).id()] = metricIndex;
-        if (!determineEventMetricUpdateStatus(config, config.event_metric(i), oldMetricProducerMap,
-                                              oldMetricProducers, metricToActivationMap,
-                                              replacedMatchers, replacedConditions,
-                                              metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-
-    // TODO: determine update status for count, gauge, value, duration metrics.
-
-    // Now, perform the update. Must iterate the metric types in the same order
-    metricIndex = 0;
-    for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
         const EventMetric& metric = config.event_metric(i);
         switch (metricsToUpdate[metricIndex]) {
             case UPDATE_PRESERVE: {
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
index 1cd0ce5..34d7e9c 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -125,23 +125,25 @@
                       std::vector<ConditionState>& conditionCache,
                       std::set<int64_t>& replacedConditions);
 
-// Function to determine if an event metric needs to be updated. Populates updateStatus.
+// Function to determine the update status (preserve/replace/new) of all metrics in the config.
 // [config]: the input StatsdConfig
-// [metric]: the current metric to be updated
 // [oldMetricProducerMap]: metric id to index mapping in the existing MetricsManager
 // [oldMetricProducers]: stores the existing MetricProducers
-// [metricToActivationMap]:  map from metric id to metric activation index.
-// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced
+// [metricToActivationMap]:  map from metric id to metric activation index
+// [replacedMatchers]: set of replaced matcher ids. metrics using these matchers must be replaced
+// [replacedConditions]: set of replaced conditions. metrics using these conditions must be replaced
+// [replacedStates]: set of replaced state ids. metrics using these states must be replaced
 // output:
-// [updateStatus]: update status for the metric. Will be changed from UPDATE_UNKNOWN after this call
+// [metricsToUpdate]: update status of each metric. Will be changed from UPDATE_UNKNOWN
 // Returns whether the function was successful or not.
-bool determineEventMetricUpdateStatus(const StatsdConfig& config, const EventMetric& metric,
+bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
                                       const unordered_map<int64_t, int>& oldMetricProducerMap,
                                       const vector<sp<MetricProducer>>& oldMetricProducers,
                                       const unordered_map<int64_t, int>& metricToActivationMap,
                                       const set<int64_t>& replacedMatchers,
                                       const set<int64_t>& replacedConditions,
-                                      UpdateStatus& updateStatus);
+                                      const set<int64_t>& replacedStates,
+                                      vector<UpdateStatus>& metricsToUpdate);
 
 // Update MetricProducers.
 // input:
diff --git a/cmds/statsd/tests/condition/ConditionTimer_test.cpp b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
index ea02cd3..46dc9a9 100644
--- a/cmds/statsd/tests/condition/ConditionTimer_test.cpp
+++ b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
@@ -35,11 +35,11 @@
     EXPECT_EQ(0, timer.mTimerNs);
 
     timer.onConditionChanged(true, ct_start_time + 5);
-    EXPECT_EQ(ct_start_time + 5, timer.mLastConditionTrueTimestampNs);
+    EXPECT_EQ(ct_start_time + 5, timer.mLastConditionChangeTimestampNs);
     EXPECT_EQ(true, timer.mCondition);
 
     EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
-    EXPECT_EQ(ct_start_time + 100, timer.mLastConditionTrueTimestampNs);
+    EXPECT_EQ(ct_start_time + 100, timer.mLastConditionChangeTimestampNs);
     EXPECT_EQ(true, timer.mCondition);
 }
 
@@ -51,7 +51,7 @@
     EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
     EXPECT_EQ(true, timer.mCondition);
     EXPECT_EQ(0, timer.mTimerNs);
-    EXPECT_EQ(ct_start_time, timer.mLastConditionTrueTimestampNs);
+    EXPECT_EQ(ct_start_time, timer.mLastConditionChangeTimestampNs);
 
     timer.onConditionChanged(false, ct_start_time + 5);
     EXPECT_EQ(5, timer.mTimerNs);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index b166cc1..6cf4192 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -93,6 +93,13 @@
     }
 }
 
+static void assertConditionTimer(const ConditionTimer& conditionTimer, bool condition,
+                                 int64_t timerNs, int64_t lastConditionTrueTimestampNs) {
+    EXPECT_EQ(condition, conditionTimer.mCondition);
+    EXPECT_EQ(timerNs, conditionTimer.mTimerNs);
+    EXPECT_EQ(lastConditionTrueTimestampNs, conditionTimer.mLastConditionChangeTimestampNs);
+}
+
 }  // anonymous namespace
 
 class ValueMetricProducerTestHelper {
@@ -3967,33 +3974,37 @@
             // Screen state change to ON.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
                 return true;
             }))
             // Screen state change to OFF.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 9));
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 9));
                 return true;
             }))
             // Screen state change to ON.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
                 return true;
             }))
             // Dump report requested.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
                 return true;
             }));
 
@@ -4025,12 +4036,13 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
 
     // Bucket status after screen state change kStateUnknown->ON.
     auto screenEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+            bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
     StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {}
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4040,34 +4052,13 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
               itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, kStateUnknown}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-
-    // Bucket status after screen state change ON->OFF.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
     // Value for dimension, state key {{}, ON}
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+    EXPECT_EQ(0, it->second.intervals.size());
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
     it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4076,9 +4067,52 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
+
+    // Bucket status after screen state change ON->OFF.
+    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+                                                android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    StateManager::getInstance().onLogEvent(*screenEvent);
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension key {}
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, OFF}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_EQ(0, it->second.intervals.size());
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+    // Value for dimension, state key {{}, ON}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_TRUE(it->second.intervals[0].hasValue);
+    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+    // Value for dimension, state key {{}, kStateUnknown}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_TRUE(it->second.intervals[0].hasValue);
+    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Bucket status after screen state change OFF->ON.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
+    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
     StateManager::getInstance().onLogEvent(*screenEvent);
     ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
@@ -4098,6 +4132,8 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(12, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 15 * NS_PER_SEC);
     // Value for dimension, state key {{}, ON}
     it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4106,6 +4142,8 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, true, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 15 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
     it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4114,37 +4152,46 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Start dump report and check output.
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS, &strSet, &output);
+    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
 
     StatsLogReport report = outputStreamToProto(&output);
     EXPECT_TRUE(report.has_value_metrics());
     ASSERT_EQ(3, report.value_metrics().data_size());
 
+    // {{}, kStateUnknown}
     auto data = report.value_metrics().data(0);
     ASSERT_EQ(1, data.bucket_info_size());
     EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {{}, ON}
     data = report.value_metrics().data(1);
     ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
     EXPECT_EQ(13, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {{}, OFF}
     data = report.value_metrics().data(2);
     ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
     EXPECT_EQ(12, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 }
 
 /*
@@ -4169,9 +4216,10 @@
             // Screen state change to ON.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
                 return true;
             }))
             // Screen state change to VR has no pull because it is in the same
@@ -4183,17 +4231,19 @@
             // Screen state change to OFF.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
                 return true;
             }))
             // Dump report requested.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
                 data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
                 return true;
             }));
 
@@ -4236,12 +4286,13 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
 
     // Bucket status after screen state change kStateUnknown->ON.
     auto screenEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+            bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
     StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {}
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4251,20 +4302,29 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(screenOnGroup.group_id(),
               itBase->second.currentState.getValues()[0].mValue.long_value);
+    // Value for dimension, state key {{}, ON GROUP}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(screenOnGroup.group_id(),
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
+    it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Bucket status after screen state change ON->VR.
     // Both ON and VR are in the same state group, so the base should not change.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
+    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
                                                 android::view::DisplayStateEnum::DISPLAY_STATE_VR);
     StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {}
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4274,20 +4334,29 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(screenOnGroup.group_id(),
               itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, ON GROUP}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(screenOnGroup.group_id(),
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
+    it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Bucket status after screen state change VR->ON.
     // Both ON and VR are in the same state group, so the base should not change.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12,
+    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12 * NS_PER_SEC,
                                                 android::view::DisplayStateEnum::DISPLAY_STATE_ON);
     StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {}
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4297,19 +4366,28 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(screenOnGroup.group_id(),
               itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, ON GROUP}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(screenOnGroup.group_id(),
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
+    it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Bucket status after screen state change VR->OFF.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
+    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
                                                 android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
     StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {}
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4319,13 +4397,22 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(screenOffGroup.group_id(),
               itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, OFF GROUP}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(screenOffGroup.group_id(),
+              it->first.getStateValuesKey().getValues()[0].mValue.long_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 15 * NS_PER_SEC);
     // Value for dimension, state key {{}, ON GROUP}
+    it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(screenOnGroup.group_id(),
               it->first.getStateValuesKey().getValues()[0].mValue.long_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(16, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 15 * NS_PER_SEC);
     // Value for dimension, state key {{}, kStateUnknown}
     it++;
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4334,37 +4421,46 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+                         bucketStartTimeNs + 5 * NS_PER_SEC);
 
     // Start dump report and check output.
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS, &strSet, &output);
+    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
 
     StatsLogReport report = outputStreamToProto(&output);
     EXPECT_TRUE(report.has_value_metrics());
     ASSERT_EQ(3, report.value_metrics().data_size());
 
+    // {{}, kStateUnknown}
     auto data = report.value_metrics().data(0);
     ASSERT_EQ(1, data.bucket_info_size());
     EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {{}, ON GROUP}
     data = report.value_metrics().data(1);
     ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
     EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_group_id());
     EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {{}, OFF GROUP}
     data = report.value_metrics().data(2);
     ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
     EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
     EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_group_id());
     EXPECT_EQ(screenOffGroup.group_id(), data.slice_by_state(0).group_id());
+    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 }
 
 /*
@@ -4386,6 +4482,35 @@
     auto fieldsInState = stateLink->mutable_fields_in_state();
     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
 
+    /*
+    NOTE: "1" denotes uid 1 and "2" denotes uid 2.
+                    bucket # 1                            bucket # 2
+    10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
+    |------------------------------------------|---------------------------------|--
+
+                                                                                    (kStateUnknown)
+    1
+    |-------------|
+          20
+
+    2
+    |----------------------------|
+                 40
+
+                                                                                    (FOREGROUND)
+                  1                                                       1
+                  |----------------------------|-------------|            |------|
+                               40                     20                     10
+
+
+                                                                                    (BACKGROUND)
+                                                             1
+                                                             |------------|
+                                                                   20
+                                 2
+                                 |-------------|---------------------------------|
+                                       20                      50
+    */
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
     EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
             // ValueMetricProducer initialized.
@@ -4400,64 +4525,64 @@
             // Uid 1 process state change from kStateUnknown -> Foreground
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
                 data->clear();
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 1 /*uid*/, 6));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+                                                       1 /*uid*/, 6));
 
                 // This event should be skipped.
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 2 /*uid*/, 8));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+                                                       2 /*uid*/, 8));
                 return true;
             }))
             // Uid 2 process state change from kStateUnknown -> Background
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40);
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
                 data->clear();
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40, 2 /*uid*/, 9));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+                                                       2 /*uid*/, 9));
 
                 // This event should be skipped.
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40, 1 /*uid*/, 12));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+                                                       1 /*uid*/, 12));
                 return true;
             }))
             // Uid 1 process state change from Foreground -> Background
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20);
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20 * NS_PER_SEC);
                 data->clear();
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20, 1 /*uid*/, 13));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
+                                                       1 /*uid*/, 13));
 
                 // This event should be skipped.
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20, 2 /*uid*/, 11));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
+                                                       2 /*uid*/, 11));
                 return true;
             }))
             // Uid 1 process state change from Background -> Foreground
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40);
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40 * NS_PER_SEC);
                 data->clear();
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40, 1 /*uid*/, 17));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
+                                                       1 /*uid*/, 17));
 
                 // This event should be skipped.
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40, 2 /*uid */, 15));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
+                                                       2 /*uid */, 15));
                 return true;
             }))
             // Dump report pull.
             .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
                                 vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50);
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
                 data->clear();
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50, 2 /*uid*/, 20));
-                data->push_back(
-                        CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50, 1 /*uid*/, 21));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
+                                                       2 /*uid*/, 20));
+                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
+                                                       1 /*uid*/, 21));
                 return true;
             }));
 
@@ -4489,6 +4614,7 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
     // Base for dimension key {uid 2}
     it++;
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4505,12 +4631,14 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
 
     // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
-    auto uidProcessEvent = CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+    auto uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
     StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
     // Base for dimension key {uid 1}.
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4528,8 +4656,18 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+    // Value for key {uid 1, FOREGROUND}.
+    it++;
+    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
 
-    // Base for dimension key {uid 2}
+    // Base for dimension key {uid 2}.
     it++;
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
     EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
@@ -4538,22 +4676,42 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, kStateUnknown}
+    // Value for key {uid 2, kStateUnknown}.
     ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
 
     // Bucket status after uid 2 process state change kStateUnknown -> Background.
-    uidProcessEvent = CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 40, 2 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 40 * NS_PER_SEC, 2 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
     StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {uid 1}.
+    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension key {uid 2}.
     it = valueProducer->mCurrentSlicedBucket.begin();
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
     EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {uid 2, BACKGROUND}.
+    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
+
+    // Base for dimension key {uid 1}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
     EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
     EXPECT_TRUE(itBase->second.hasCurrentState);
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
@@ -4563,26 +4721,33 @@
     ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
 
-    // Base for dimension key {uid 2}
+    // Value for key {uid 1, FOREGROUND}.
     it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
+    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
     // Value for key {uid 2, kStateUnknown}
+    it++;
     ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 40 * NS_PER_SEC,
+                         bucketStartTimeNs + 40 * NS_PER_SEC);
 
     // Pull at end of first bucket.
     vector<shared_ptr<LogEvent>> allData;
@@ -4612,6 +4777,8 @@
     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
 
     // Base for dimension key {uid 1}
     it++;
@@ -4629,6 +4796,8 @@
     EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+    EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
 
     // Value for key {uid 1, FOREGROUND}
     it++;
@@ -4638,6 +4807,8 @@
     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
 
     // Value for key {uid 2, kStateUnknown}
     it++;
@@ -4647,13 +4818,16 @@
     EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
+    EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
 
     // Bucket status after uid 1 process state change from Foreground -> Background.
-    uidProcessEvent = CreateUidProcessStateChangedEvent(
-            bucket2StartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
     StateManager::getInstance().onLogEvent(*uidProcessEvent);
 
-    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
     ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
     ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
     // Base for dimension key {uid 2}.
@@ -4672,6 +4846,8 @@
     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
     // Base for dimension key {uid 1}
     it++;
     itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4688,6 +4864,17 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {uid 1, BACKGROUND}
+    it++;
+    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 20 * NS_PER_SEC);
+
     // Value for key {uid 1, FOREGROUND}
     it++;
     ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4697,6 +4884,9 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucket2StartTimeNs + 20 * NS_PER_SEC);
+
     // Value for key {uid 2, kStateUnknown}
     it++;
     ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4705,10 +4895,12 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
 
     // Bucket status after uid 1 process state change Background->Foreground.
-    uidProcessEvent = CreateUidProcessStateChangedEvent(
-            bucket2StartTimeNs + 40, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 40 * NS_PER_SEC, 1 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
     StateManager::getInstance().onLogEvent(*uidProcessEvent);
 
     ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
@@ -4729,6 +4921,7 @@
     EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
 
     // Base for dimension key {uid 1}
     it++;
@@ -4746,6 +4939,7 @@
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
 
     // Value for key {uid 1, BACKGROUND}
     it++;
@@ -4756,6 +4950,8 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucket2StartTimeNs + 40 * NS_PER_SEC);
 
     // Value for key {uid 1, FOREGROUND}
     it++;
@@ -4766,6 +4962,8 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+                         bucket2StartTimeNs + 40 * NS_PER_SEC);
 
     // Value for key {uid 2, kStateUnknown}
     it++;
@@ -4774,17 +4972,20 @@
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
 
     // Start dump report and check output.
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 50, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS, &strSet, &output);
+    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
 
     StatsLogReport report = outputStreamToProto(&output);
     EXPECT_TRUE(report.has_value_metrics());
     ASSERT_EQ(5, report.value_metrics().data_size());
 
+    // {uid 1, BACKGROUND}
     auto data = report.value_metrics().data(0);
     ASSERT_EQ(1, data.bucket_info_size());
     EXPECT_EQ(4, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
@@ -4792,14 +4993,18 @@
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
               data.slice_by_state(0).value());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {uid 2, kStateUnknown}
     data = report.value_metrics().data(1);
     ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
     EXPECT_EQ(2, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {uid 1, FOREGROUND}
     data = report.value_metrics().data(2);
     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -4808,14 +5013,19 @@
     ASSERT_EQ(2, report.value_metrics().data(2).bucket_info_size());
     EXPECT_EQ(4, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
     EXPECT_EQ(7, report.value_metrics().data(2).bucket_info(1).values(0).value_long());
+    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
 
+    // {uid 1, kStateUnknown}
     data = report.value_metrics().data(3);
     ASSERT_EQ(1, report.value_metrics().data(3).bucket_info_size());
     EXPECT_EQ(3, report.value_metrics().data(3).bucket_info(0).values(0).value_long());
     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
     EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
+    // {uid 2, BACKGROUND}
     data = report.value_metrics().data(4);
     EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
     EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -4824,6 +5034,1630 @@
     ASSERT_EQ(2, report.value_metrics().data(4).bucket_info_size());
     EXPECT_EQ(6, report.value_metrics().data(4).bucket_info(0).values(0).value_long());
     EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state when data is not
+ * present in pulled data during a state change.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange) {
+    // Set up ValueMetricProducer.
+    ValueMetric metric =
+            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    /*
+    NOTE: "-" means that the data was not present in the pulled data.
+
+                             bucket # 1
+    10         20         30         40         50         60   (seconds)
+    |-------------------------------------------------------|--
+    x                                                           (kStateUnknown)
+    |-----------|
+         10
+
+                x                               x               (ON)
+                |---------------------|         |-----------|
+                           20                        10
+
+                                      -                         (OFF)
+    */
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+            // ValueMetricProducer initialized.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+                return true;
+            }))
+            // Battery saver mode state changed to ON.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
+                return true;
+            }))
+            // Battery saver mode state changed to OFF but data for dimension key {} is not present
+            // in the pulled data.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
+                data->clear();
+                return true;
+            }))
+            // Battery saver mode state changed to ON.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 7));
+                return true;
+            }))
+            // Dump report pull.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
+                return true;
+            }));
+
+    StateManager::getInstance().clear();
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithState(
+                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+    // Set up StateManager and check that StateTrackers are initialized.
+    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+                                                 valueProducer);
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+    // Bucket status after metric initialized.
+    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension key {}
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, kStateUnknown}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
+
+    // Bucket status after battery saver mode ON event.
+    unique_ptr<LogEvent> batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+    // Base for dimension key {}
+
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Bucket status after battery saver mode OFF event which is not present
+    // in the pulled data.
+    unique_ptr<LogEvent> batterySaverOffEvent =
+            CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
+
+    // Base for dimension key {}
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_FALSE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Bucket status after battery saver mode ON event.
+    batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 40 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+    // Base for dimension key {}
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 40 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Start dump report and check output.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(2, report.value_metrics().data_size());
+
+    // {{}, kStateUnknown}
+    ValueMetricData data = report.value_metrics().data(0);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+    // {{}, ON}
+    data = report.value_metrics().data(1);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test for metric that slices by state when data is not present in pulled data
+ * during an event and then a flush occurs for the current bucket. With the new
+ * condition timer behavior, a "new" MetricDimensionKey is inserted into
+ * `mCurrentSlicedBucket` before intervals are closed/added to that new
+ * MetricDimensionKey.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket) {
+    // Set up ValueMetricProducer.
+    ValueMetric metric =
+            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    /*
+    NOTE: "-" means that the data was not present in the pulled data.
+
+                             bucket # 1
+    10         20         30         40         50         60   (seconds)
+    |-------------------------------------------------------|--
+    -                                                           (kStateUnknown)
+
+                -                                               (ON)
+    */
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+            // ValueMetricProducer initialized  but data for dimension key {} is not present
+            // in the pulled data..
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+                data->clear();
+                return true;
+            }))
+            // Battery saver mode state changed to ON but data for dimension key {} is not present
+            // in the pulled data.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                return true;
+            }))
+            // Dump report pull.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
+                return true;
+            }));
+
+    StateManager::getInstance().clear();
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithState(
+                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+    // Set up StateManager and check that StateTrackers are initialized.
+    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+                                                 valueProducer);
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+    // Bucket status after metric initialized.
+    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
+
+    // Bucket status after battery saver mode ON event which is not present
+    // in the pulled data.
+    unique_ptr<LogEvent> batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+    ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+
+    // Start dump report and check output.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(0, report.value_metrics().data_size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+}
+
+TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary) {
+    // Set up ValueMetricProducer.
+    ValueMetric metric =
+            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    /*
+                 bucket # 1                         bucket # 2
+    10    20    30    40    50    60    70    80   90   100   110   120  (seconds)
+    |------------------------------------|---------------------------|--
+    x                                                                    (kStateUnknown)
+    |-----|
+      10
+          x                                              x               (ON)
+          |-----|                                        |-----------|
+             10                                               20
+                x                                                        (OFF)
+                |------------------------|
+                          40
+    */
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+            // ValueMetricProducer initialized.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+                return true;
+            }))
+            // Battery saver mode state changed to ON.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
+                return true;
+            }))
+            // Battery saver mode state changed to OFF.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 7));
+                return true;
+            }))
+            // Battery saver mode state changed to ON.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 10));
+                return true;
+            }))
+            // Dump report pull.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 15));
+                return true;
+            }));
+
+    StateManager::getInstance().clear();
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithState(
+                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+    // Set up StateManager and check that StateTrackers are initialized.
+    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+                                                 valueProducer);
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+    // Bucket status after metric initialized.
+    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for dimension, state key {{}, kStateUnknown}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
+
+    // Bucket status after battery saver mode ON event.
+    unique_ptr<LogEvent> batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Bucket status after battery saver mode OFF event.
+    unique_ptr<LogEvent> batterySaverOffEvent =
+            CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 20 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
+
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, OFF}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{}, ON}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Bucket status after battery saver mode ON event.
+    batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucket2StartTimeNs + 30 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, OFF}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
+                         bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{}, ON}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Start dump report and check output.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(3, report.value_metrics().data_size());
+
+    // {{}, kStateUnknown}
+    ValueMetricData data = report.value_metrics().data(0);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+    // {{}, ON}
+    data = report.value_metrics().data(1);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+    ASSERT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+    // {{}, OFF}
+    data = report.value_metrics().data(2);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state when data is not
+ * present in pulled data during a condition change.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange) {
+    // Set up ValueMetricProducer.
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState(
+            "BATTERY_SAVER_MODE_STATE");
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    /*
+    NOTE: "-" means that the data was not present in the pulled data.
+
+                             bucket # 1
+    10         20         30         40         50         60   (seconds)
+    |-------------------------------------------------------|--
+
+    T                                 F         T               (Condition)
+               x                                                (ON)
+               |----------------------|         -
+                         20
+    */
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+            // Battery saver mode state changed to ON.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 3));
+                return true;
+            }))
+            // Condition changed to false.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
+                data->clear();
+                data->push_back(
+                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
+                return true;
+            }))
+            // Condition changed to true but data for dimension key {} is not present in the
+            // pulled data.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+                data->clear();
+                return true;
+            }))
+            // Dump report pull.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 20));
+                return true;
+            }));
+
+    StateManager::getInstance().clear();
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
+                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
+                    ConditionState::kTrue);
+    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+    // Set up StateManager and check that StateTrackers are initialized.
+    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+                                                 valueProducer);
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+    // Bucket status after battery saver mode ON event.
+    unique_ptr<LogEvent> batterySaverOnEvent =
+            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+    // Base for dimension key {}
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket status after condition change to false.
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 30 * NS_PER_SEC);
+    // Base for dimension key {}
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_TRUE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket status after condition change to true.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 40 * NS_PER_SEC);
+    // Base for dimension key {}
+    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_FALSE(itBase->second.hasCurrentState);
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, ON}
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Start dump report and check output.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(1, report.value_metrics().data_size());
+
+    // {{}, ON}
+    ValueMetricData data = report.value_metrics().data(0);
+    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state with a primary field,
+ * condition, and has multiple dimensions.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions) {
+    // Set up ValueMetricProducer.
+    ValueMetric metric =
+            ValueMetricProducerTestHelper::createMetricWithConditionAndState("UID_PROCESS_STATE");
+    metric.mutable_dimensions_in_what()->set_field(tagId);
+    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+    metric.mutable_dimensions_in_what()->add_child()->set_field(3);
+
+    MetricStateLink* stateLink = metric.add_state_link();
+    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+    auto fieldsInWhat = stateLink->mutable_fields_in_what();
+    *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
+    auto fieldsInState = stateLink->mutable_fields_in_state();
+    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+    /*
+                    bucket # 1                            bucket # 2
+    10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
+    |------------------------------------------|---------------------------------|--
+
+    T                           F   T                                               (Condition)
+                                                                                    (FOREGROUND)
+           x                                                                        {1, 14}
+           |------|
+              10
+
+           x                                                                        {1, 16}
+           |------|
+              10
+                                                                   x                {2, 8}
+                                                                   |-------------|
+                                                                         20
+
+                                                                                    (BACKGROUND)
+                  x                                                                 {1, 14}
+                  |-------------|   |----------|---------------------------------|
+                        20              15                     50
+
+                  x                                                                 {1, 16}
+                  |-------------|   |----------|---------------------------------|
+                        20              15                     50
+
+                     x                                                              {2, 8}
+                     |----------|   |----------|-------------------|
+                         15             15              30
+    */
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+            // Uid 1 process state change from kStateUnknown -> Foreground
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+                                                         1 /*uid*/, 3, 14 /*tag*/));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+                                                         1 /*uid*/, 3, 16 /*tag*/));
+
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+                                                         2 /*uid*/, 5, 8 /*tag*/));
+                return true;
+            }))
+            // Uid 1 process state change from Foreground -> Background
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+                                                         1 /*uid*/, 5, 14 /*tag*/));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+                                                         1 /*uid*/, 5, 16 /*tag*/));
+
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+                                                         2 /*uid*/, 7, 8 /*tag*/));
+
+                return true;
+            }))
+            // Uid 2 process state change from kStateUnknown -> Background
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 25 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+                                                         2 /*uid*/, 9, 8 /*tag*/));
+
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+                                                         1 /*uid*/, 9, 14 /* tag */));
+
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+                                                         1 /*uid*/, 9, 16 /* tag */));
+
+                return true;
+            }))
+            // Condition changed to false.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+                                                         1 /*uid*/, 11, 14 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+                                                         1 /*uid*/, 11, 16 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+                                                         2 /*uid*/, 11, 8 /*tag*/));
+
+                return true;
+            }))
+            // Condition changed to true.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 45 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+                                                         1 /*uid*/, 13, 14 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+                                                         1 /*uid*/, 13, 16 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+                                                         2 /*uid*/, 13, 8 /*tag*/));
+                return true;
+            }))
+            // Uid 2 process state change from Background -> Foreground
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /*uid*/, 18, 8 /*tag*/));
+
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 14 /* tag */));
+                // This event should be skipped.
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 16 /* tag */));
+
+                return true;
+            }))
+            // Dump report pull.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 14 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 16 /* tag */));
+                data->push_back(CreateThreeValueLogEvent(
+                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 2 /*uid*/, 21, 8 /*tag*/));
+                return true;
+            }));
+
+    StateManager::getInstance().clear();
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
+                    pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {}, ConditionState::kTrue);
+    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+    // Set up StateManager and check that StateTrackers are initialized.
+    StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+    // Condition is true.
+    // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
+    auto uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC, 1 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+    StateManager::getInstance().onLogEvent(*uidProcessEvent);
+    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension {uid 1, tag 16}.
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket status after uid 1 process state change Foreground -> Background.
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+    StateManager::getInstance().onLogEvent(*uidProcessEvent);
+    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(6UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension {uid 1, tag 16}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket status after uid 2 process state change kStateUnknown -> Background.
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 2 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+    StateManager::getInstance().onLogEvent(*uidProcessEvent);
+    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension {uid 2, tag 8}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 2, uid 8}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 25 * NS_PER_SEC);
+
+    // Value for key {{uid 2, uid 8}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension {uid 1, tag 16}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket 1 status after condition change to false.
+    // All condition timers should be turned off.
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
+    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension {uid 2, tag 8}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 2, uid 8}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 15 * NS_PER_SEC,
+                         bucketStartTimeNs + 40 * NS_PER_SEC);
+
+    // Value for key {{uid 2, uid 8}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension {uid 1, tag 16}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 40 * NS_PER_SEC);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 40 * NS_PER_SEC);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket 1 status after condition change to true.
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 45 * NS_PER_SEC);
+    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+    // Base for dimension {uid 2, tag 8}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 2, uid 8}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 15 * NS_PER_SEC,
+                         bucketStartTimeNs + 45 * NS_PER_SEC);
+
+    // Value for key {{uid 2, uid 8}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension {uid 1, tag 16}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 45 * NS_PER_SEC);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+                         bucketStartTimeNs + 45 * NS_PER_SEC);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Pull at end of first bucket.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(
+            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 14 /* tag */));
+    allData.push_back(
+            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 16 /* tag */));
+    allData.push_back(
+            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 13, 8 /*tag*/));
+    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
+
+    // Buckets flushed after end of first bucket.
+    // All condition timers' behavior should rollover to bucket 2.
+    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(5UL, valueProducer->mPastBuckets.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+    // Base for dimension {uid 2, tag 8}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 2, uid 8}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+    EXPECT_EQ(30 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+    // Value for key {{uid 2, uid 8}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension {uid 1, tag 16}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+    EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+    EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+    EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+    EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Bucket 2 status after uid 2 process state change Background->Foreground.
+    uidProcessEvent =
+            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /* uid */,
+                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+    StateManager::getInstance().onLogEvent(*uidProcessEvent);
+
+    ASSERT_EQ(9UL, valueProducer->mCurrentSlicedBucket.size());
+    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+    // Base for dimension {uid 2, tag 8}.
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 2, uid 8}, FOREGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{uid 2, uid 8}, BACKGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
+                         bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+    // Value for key {{uid 2, uid 8}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Base for dimension {uid 1, tag 16}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, uid 16}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
+    // Base for dimension key {uid 1, tag 14}.
+    it++;
+    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{uid 1, tag 14}, BACKGROUND}.
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
+    // Value for key {{uid 1, uid 16}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 16}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Value for key {{uid 1, tag 14}, FOREGROUND}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+    // Value for key {{uid 1, tag 14}, kStateUnknown}.
+    it++;
+    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+    // Start dump report and check output.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+                                &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(6, report.value_metrics().data_size());
+
+    // {{uid 1, tag 14}, FOREGROUND}.
+    auto data = report.value_metrics().data(0);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+    // {{uid 1, tag 16}, BACKGROUND}.
+    data = report.value_metrics().data(1);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+    // {{uid 1, tag 14}, BACKGROUND}.
+    data = report.value_metrics().data(2);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+    // {{uid 1, tag 16}, FOREGROUND}.
+    data = report.value_metrics().data(3);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+    // {{uid 2, tag 8}, FOREGROUND}.
+    data = report.value_metrics().data(4);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+    // {{uid 2, tag 8}, BACKGROUND}.
+    data = report.value_metrics().data(5);
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+              data.slice_by_state(0).value());
+    ASSERT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
 }
 
 TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
@@ -4894,15 +6728,23 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(BatterySaverModeStateChanged::ON,
               itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, -1}
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    // Value for key {{}, ON}
+    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it =
             valueProducer->mCurrentSlicedBucket.begin();
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+    // Value for key {{}, -1}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
 
     // Bucket status after battery saver mode OFF event.
     unique_ptr<LogEvent> batterySaverOffEvent =
@@ -4917,15 +6759,27 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
               itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    // Value for key {{}, OFF}
+    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
     it = valueProducer->mCurrentSlicedBucket.begin();
     EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
     ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+    // Value for key {{}, ON}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
     EXPECT_EQ(BatterySaverModeStateChanged::ON,
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucketStartTimeNs + 30 * NS_PER_SEC);
+    // Value for key {{}, -1}
+    it++;
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
 
     // Pull at end of first bucket.
     vector<shared_ptr<LogEvent>> allData;
@@ -4944,6 +6798,15 @@
     ASSERT_EQ(1, itBase->second.currentState.getValues().size());
     EXPECT_EQ(BatterySaverModeStateChanged::OFF,
               itBase->second.currentState.getValues()[0].mValue.int_value);
+    // Value for key {{}, OFF}
+    it = valueProducer->mCurrentSlicedBucket.begin();
+    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+    // Value for key {{}, ON}
+    it++;
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+    // Value for key {{}, -1}
+    it++;
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
 
     // Bucket 2 status after condition change to false.
     valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
@@ -4964,6 +6827,19 @@
               it->first.getStateValuesKey().getValues()[0].mValue.int_value);
     EXPECT_TRUE(it->second.intervals[0].hasValue);
     EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+                         bucket2StartTimeNs + 10 * NS_PER_SEC);
+    // Value for key {{}, ON}
+    it++;
+    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+    EXPECT_EQ(BatterySaverModeStateChanged::ON,
+              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+    EXPECT_FALSE(it->second.intervals[0].hasValue);
+    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+    // Value for key {{}, -1}
+    it++;
+    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
 
     // Start dump report and check output.
     ProtoOutputStream output;
@@ -4982,6 +6858,7 @@
     EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
     ASSERT_EQ(1, data.bucket_info_size());
     EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
 
     data = report.value_metrics().data(1);
     EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
@@ -4990,6 +6867,8 @@
     ASSERT_EQ(2, data.bucket_info_size());
     EXPECT_EQ(6, data.bucket_info(0).values(0).value_long());
     EXPECT_EQ(4, data.bucket_info(1).values(0).value_long());
+    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
 }
 
 /*
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index 076000f..65e5875 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -920,14 +920,13 @@
     // Create an initial config.
     EXPECT_TRUE(initConfig(config));
 
-    set<int64_t> replacedMatchers;
-    set<int64_t> replacedConditions;
     unordered_map<int64_t, int> metricToActivationMap;
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_PRESERVE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+                                                 metricToActivationMap,
+                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+                                                 /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
 }
 
 TEST_F(ConfigUpdateTest, TestEventMetricActivationAdded) {
@@ -957,14 +956,13 @@
     eventActivation->set_atom_matcher_id(startMatcher.id());
     eventActivation->set_ttl_seconds(5);
 
-    set<int64_t> replacedMatchers;
-    set<int64_t> replacedConditions;
     unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_REPLACE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+                                                 metricToActivationMap,
+                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+                                                 /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
 }
 
 TEST_F(ConfigUpdateTest, TestEventMetricWhatChanged) {
@@ -987,14 +985,13 @@
     // Create an initial config.
     EXPECT_TRUE(initConfig(config));
 
-    set<int64_t> replacedMatchers = {whatMatcher.id()};
-    set<int64_t> replacedConditions;
     unordered_map<int64_t, int> metricToActivationMap;
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_REPLACE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(
+            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+            /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
+            /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
 }
 
 TEST_F(ConfigUpdateTest, TestEventMetricConditionChanged) {
@@ -1017,14 +1014,13 @@
     // Create an initial config.
     EXPECT_TRUE(initConfig(config));
 
-    set<int64_t> replacedMatchers;
-    set<int64_t> replacedConditions = {predicate.id()};
     unordered_map<int64_t, int> metricToActivationMap;
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_REPLACE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(
+            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+            /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
+            /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
 }
 
 TEST_F(ConfigUpdateTest, TestMetricConditionLinkDepsChanged) {
@@ -1054,14 +1050,13 @@
     // Create an initial config.
     EXPECT_TRUE(initConfig(config));
 
-    set<int64_t> replacedMatchers;
-    set<int64_t> replacedConditions = {linkPredicate.id()};
     unordered_map<int64_t, int> metricToActivationMap;
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_REPLACE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(
+            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+            /*replacedMatchers*/ {}, /*replacedConditions=*/{linkPredicate.id()},
+            /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
 }
 
 TEST_F(ConfigUpdateTest, TestEventMetricActivationDepsChange) {
@@ -1090,14 +1085,13 @@
     // Create an initial config.
     EXPECT_TRUE(initConfig(config));
 
-    set<int64_t> replacedMatchers = {startMatcher.id()};  // The activation matcher is replaced.
-    set<int64_t> replacedConditions;
     unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
-    UpdateStatus status = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
-                                                 oldMetricProducers, metricToActivationMap,
-                                                 replacedMatchers, replacedConditions, status));
-    EXPECT_EQ(status, UPDATE_REPLACE);
+    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+    EXPECT_TRUE(determineAllMetricUpdateStatuses(
+            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+            /*replacedMatchers*/ {startMatcher.id()}, /*replacedConditions=*/{},
+            /*replacedStates=*/{}, metricsToUpdate));
+    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
 }
 
 TEST_F(ConfigUpdateTest, TestUpdateEventMetrics) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 312d122..bb194a5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3271,12 +3271,6 @@
         sendMessage(H.CLEAN_UP_CONTEXT, cci);
     }
 
-    @Override
-    public void handleFixedRotationAdjustments(@NonNull IBinder token,
-            @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
-        handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */);
-    }
-
     /**
      * Applies the rotation adjustments to override display information in resources belong to the
      * provided token. If the token is activity token, the adjustments also apply to application
@@ -3286,51 +3280,39 @@
      * @param fixedRotationAdjustments The information to override the display adjustments of
      *                                 corresponding resources. If it is null, the exiting override
      *                                 will be cleared.
-     * @param overrideConfig The override configuration of activity. It is used to override
-     *                       application configuration. If it is non-null, it means the token is
-     *                       confirmed as activity token. Especially when launching new activity,
-     *                       {@link #mActivities} hasn't put the new token.
      */
-    private void handleFixedRotationAdjustments(@NonNull IBinder token,
-            @Nullable FixedRotationAdjustments fixedRotationAdjustments,
-            @Nullable Configuration overrideConfig) {
-        // The element of application configuration override is set only if the application
-        // adjustments are needed, because activity already has its own override configuration.
-        final Configuration[] appConfigOverride;
-        final Consumer<DisplayAdjustments> override;
-        if (fixedRotationAdjustments != null) {
-            appConfigOverride = new Configuration[1];
-            override = displayAdjustments -> {
-                displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
-                if (appConfigOverride[0] != null) {
-                    displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]);
-                }
-            };
-        } else {
-            appConfigOverride = null;
-            override = null;
-        }
+    @Override
+    public void handleFixedRotationAdjustments(@NonNull IBinder token,
+            @Nullable FixedRotationAdjustments fixedRotationAdjustments) {
+        final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
+                ? displayAdjustments -> displayAdjustments
+                        .setFixedRotationAdjustments(fixedRotationAdjustments)
+                : null;
         if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
             // No resources are associated with the token.
             return;
         }
-        if (overrideConfig == null) {
-            final ActivityClientRecord r = mActivities.get(token);
-            if (r == null) {
-                // It is not an activity token. Nothing to do for application.
-                return;
-            }
-            overrideConfig = r.overrideConfig;
-        }
-        if (appConfigOverride != null) {
-            appConfigOverride[0] = overrideConfig;
+        if (mActivities.get(token) == null) {
+            // Nothing to do for application if it is not an activity token.
+            return;
         }
 
-        // Apply the last override to application resources for compatibility. Because the Resources
-        // of Display can be from application, e.g.
-        //    applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
-        // and the deprecated usage:
-        //    applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
+        overrideApplicationDisplayAdjustments(token, override);
+    }
+
+    /**
+     * Applies the last override to application resources for compatibility. Because the Resources
+     * of Display can be from application, e.g.
+     *   applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId)
+     * and the deprecated usage:
+     *   applicationContext.getSystemService(WindowManager.class).getDefaultDisplay();
+     *
+     * @param token The owner and target of the override.
+     * @param override The display adjustments override for application resources. If it is null,
+     *                 the override of the token will be removed and pop the last one to use.
+     */
+    private void overrideApplicationDisplayAdjustments(@NonNull IBinder token,
+            @Nullable Consumer<DisplayAdjustments> override) {
         final Consumer<DisplayAdjustments> appOverride;
         if (mActiveRotationAdjustments == null) {
             mActiveRotationAdjustments = new ArrayList<>(2);
@@ -3559,8 +3541,13 @@
         // The rotation adjustments must be applied before creating the activity, so the activity
         // can get the adjusted display info during creation.
         if (r.mPendingFixedRotationAdjustments != null) {
-            handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments,
-                    r.overrideConfig);
+            // The adjustments should have been set by handleLaunchActivity, so the last one is the
+            // override for activity resources.
+            if (mActiveRotationAdjustments != null && !mActiveRotationAdjustments.isEmpty()) {
+                mResourcesManager.overrideTokenDisplayAdjustments(r.token,
+                        mActiveRotationAdjustments.get(
+                                mActiveRotationAdjustments.size() - 1).second);
+            }
             r.mPendingFixedRotationAdjustments = null;
         }
 
@@ -3599,6 +3586,13 @@
             mProfiler.startProfiling();
         }
 
+        if (r.mPendingFixedRotationAdjustments != null) {
+            // The rotation adjustments must be applied before handling configuration, so process
+            // level display metrics can be adjusted.
+            overrideApplicationDisplayAdjustments(r.token, adjustments ->
+                    adjustments.setFixedRotationAdjustments(r.mPendingFixedRotationAdjustments));
+        }
+
         // Make sure we are running with the most recent config.
         handleConfigurationChanged(null, null);
 
@@ -5735,7 +5729,15 @@
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
                     + config);
 
-            mResourcesManager.applyConfigurationToResourcesLocked(config, compat);
+            final Resources appResources = mInitialApplication.getResources();
+            if (appResources.hasOverrideDisplayAdjustments()) {
+                // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments,
+                // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated
+                // configuration also needs to set to the adjustments for consistency.
+                appResources.getDisplayAdjustments().getConfiguration().updateFrom(config);
+            }
+            mResourcesManager.applyConfigurationToResourcesLocked(config, compat,
+                    appResources.getDisplayAdjustments());
             updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                     mResourcesManager.getConfiguration().getLocales());
 
@@ -7359,7 +7361,8 @@
                 // We need to apply this change to the resources immediately, because upon returning
                 // the view hierarchy will be informed about it.
                 if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
-                        null /* compat */)) {
+                        null /* compat */,
+                        mInitialApplication.getResources().getDisplayAdjustments())) {
                     updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                             mResourcesManager.getConfiguration().getLocales());
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index cf5a7b6..e94fd45 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -187,16 +187,6 @@
     private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache";
 
     /**
-     * Special intent extra that critical system apps can use to hide the notification for a
-     * foreground service. This extra should be placed in the intent passed into {@link
-     * #startForegroundService(Intent)}.
-     *
-     * @hide
-     */
-    private static final String EXTRA_HIDDEN_FOREGROUND_SERVICE =
-            "android.intent.extra.HIDDEN_FOREGROUND_SERVICE";
-
-    /**
      * Map from package name, to preference name, to cached preferences.
      */
     @GuardedBy("ContextImpl.class")
@@ -1717,12 +1707,9 @@
         try {
             validateServiceIntent(service);
             service.prepareToLeaveProcess(this);
-            final boolean hideForegroundNotification = requireForeground
-                    && service.getBooleanExtra(EXTRA_HIDDEN_FOREGROUND_SERVICE, false);
             ComponentName cn = ActivityManager.getService().startService(
                     mMainThread.getApplicationThread(), service,
                     service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
-                    hideForegroundNotification,
                     getOpPackageName(), getAttributionTag(), user.getIdentifier());
             if (cn != null) {
                 if (cn.getPackageName().equals("!")) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c1e6f52..95bbebe 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -156,8 +156,7 @@
     boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta);
     PendingIntent getRunningServiceControlPanel(in ComponentName service);
     ComponentName startService(in IApplicationThread caller, in Intent service,
-            in String resolvedType, boolean requireForeground,
-            boolean hideForegroundNotification, in String callingPackage,
+            in String resolvedType, boolean requireForeground, in String callingPackage,
             in String callingFeatureId, int userId);
     @UnsupportedAppUsage
     int stopService(in IApplicationThread caller, in Intent service,
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 4c9e400..9eeb9f6 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -52,4 +52,6 @@
     void dropShellPermissionIdentity();
     // Called from the system process.
     oneway void shutdown();
+    void executeShellCommandWithStderr(String command, in ParcelFileDescriptor sink,
+                in ParcelFileDescriptor source, in ParcelFileDescriptor stderrSink);
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 9e4ab33..b267840 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1262,12 +1262,18 @@
     public final boolean applyConfigurationToResources(@NonNull Configuration config,
             @Nullable CompatibilityInfo compat) {
         synchronized(this) {
-            return applyConfigurationToResourcesLocked(config, compat);
+            return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */);
         }
     }
 
     public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
-                                                             @Nullable CompatibilityInfo compat) {
+            @Nullable CompatibilityInfo compat) {
+        return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */);
+    }
+
+    /** Applies the global configuration to the managed resources. */
+    public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
+            @Nullable CompatibilityInfo compat, @Nullable DisplayAdjustments adjustments) {
         try {
             Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
                     "ResourcesManager#applyConfigurationToResourcesLocked");
@@ -1291,6 +1297,11 @@
             }
 
             DisplayMetrics displayMetrics = getDisplayMetrics();
+            if (adjustments != null) {
+                // Currently the only case where the adjustment takes effect is to simulate placing
+                // an app in a rotated display.
+                adjustments.adjustGlobalAppMetrics(displayMetrics);
+            }
             Resources.updateSystemConfiguration(config, displayMetrics, compat);
 
             ApplicationPackageManager.configurationChanged();
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index ab997e9..4e868fe 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -25,6 +25,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
@@ -1245,7 +1246,34 @@
      * @hide
      */
     @TestApi
-    public ParcelFileDescriptor[] executeShellCommandRw(String command) {
+    public @NonNull ParcelFileDescriptor[] executeShellCommandRw(@NonNull String command) {
+        return executeShellCommandInternal(command, false /* includeStderr */);
+    }
+
+    /**
+     * Executes a shell command. This method returns three file descriptors,
+     * one that points to the standard output stream (element at index 0), one that points
+     * to the standard input stream (element at index 1), and one points to
+     * standard error stream (element at index 2). The command execution is similar
+     * to running "adb shell <command>" from a host connected to the device.
+     * <p>
+     * <strong>Note:</strong> It is your responsibility to close the returned file
+     * descriptors once you are done reading/writing.
+     * </p>
+     *
+     * @param command The command to execute.
+     * @return File descriptors (out, in, err) to the standard output/input/error streams.
+     *
+     * @hide
+     */
+    @TestApi
+    @SuppressLint("ArrayReturn") // For consistency with other APIs
+    public @NonNull ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String command) {
+        return executeShellCommandInternal(command, true /* includeStderr */);
+    }
+
+    private ParcelFileDescriptor[] executeShellCommandInternal(
+            String command, boolean includeStderr) {
         warnIfBetterCommand(command);
 
         ParcelFileDescriptor source_read = null;
@@ -1254,6 +1282,9 @@
         ParcelFileDescriptor source_write = null;
         ParcelFileDescriptor sink_write = null;
 
+        ParcelFileDescriptor stderr_source_read = null;
+        ParcelFileDescriptor stderr_sink_read = null;
+
         try {
             ParcelFileDescriptor[] pipe_read = ParcelFileDescriptor.createPipe();
             source_read = pipe_read[0];
@@ -1263,8 +1294,15 @@
             source_write = pipe_write[0];
             sink_write = pipe_write[1];
 
+            if (includeStderr) {
+                ParcelFileDescriptor[] stderr_read = ParcelFileDescriptor.createPipe();
+                stderr_source_read = stderr_read[0];
+                stderr_sink_read = stderr_read[1];
+            }
+
             // Calling out without a lock held.
-            mUiAutomationConnection.executeShellCommand(command, sink_read, source_write);
+            mUiAutomationConnection.executeShellCommandWithStderr(
+                    command, sink_read, source_write, stderr_sink_read);
         } catch (IOException ioe) {
             Log.e(LOG_TAG, "Error executing shell command!", ioe);
         } catch (RemoteException re) {
@@ -1272,11 +1310,15 @@
         } finally {
             IoUtils.closeQuietly(sink_read);
             IoUtils.closeQuietly(source_write);
+            IoUtils.closeQuietly(stderr_sink_read);
         }
 
-        ParcelFileDescriptor[] result = new ParcelFileDescriptor[2];
+        ParcelFileDescriptor[] result = new ParcelFileDescriptor[includeStderr ? 3 : 2];
         result[0] = source_read;
         result[1] = sink_write;
+        if (includeStderr) {
+            result[2] = stderr_source_read;
+        }
         return result;
     }
 
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 70d5201..255b93f 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -372,6 +372,13 @@
     @Override
     public void executeShellCommand(final String command, final ParcelFileDescriptor sink,
             final ParcelFileDescriptor source) throws RemoteException {
+        executeShellCommandWithStderr(command, sink, source, null /* stderrSink */);
+    }
+
+    @Override
+    public void executeShellCommandWithStderr(final String command, final ParcelFileDescriptor sink,
+            final ParcelFileDescriptor source, final ParcelFileDescriptor stderrSink)
+            throws RemoteException {
         synchronized (mLock) {
             throwIfCalledByNotTrustedUidLocked();
             throwIfShutdownLocked();
@@ -409,6 +416,18 @@
             writeToProcess = null;
         }
 
+        // Read from process stderr and write to pipe
+        final Thread readStderrFromProcess;
+        if (stderrSink != null) {
+            InputStream sink_in = process.getErrorStream();
+            OutputStream sink_out = new FileOutputStream(stderrSink.getFileDescriptor());
+
+            readStderrFromProcess = new Thread(new Repeater(sink_in, sink_out));
+            readStderrFromProcess.start();
+        } else {
+            readStderrFromProcess = null;
+        }
+
         Thread cleanup = new Thread(new Runnable() {
             @Override
             public void run() {
@@ -419,14 +438,18 @@
                     if (readFromProcess != null) {
                         readFromProcess.join();
                     }
+                    if (readStderrFromProcess != null) {
+                        readStderrFromProcess.join();
+                    }
                 } catch (InterruptedException exc) {
                     Log.e(TAG, "At least one of the threads was interrupted");
                 }
                 IoUtils.closeQuietly(sink);
                 IoUtils.closeQuietly(source);
+                IoUtils.closeQuietly(stderrSink);
                 process.destroy();
-                }
-            });
+            }
+        });
         cleanup.start();
     }
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index af2b905..24282365 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -793,4 +793,6 @@
     List<String> getMimeGroup(String packageName, String group);
 
     boolean isAutoRevokeWhitelisted(String packageName);
+
+    void grantImplicitAccess(int queryingUid, String visibleAuthority);
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index da56abf..a9f1439 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1878,6 +1878,7 @@
 
         /** {@hide} */
         @SystemApi
+        @TestApi
         public void setInstallAsInstantApp(boolean isInstantApp) {
             if (isInstantApp) {
                 installFlags |= PackageManager.INSTALL_INSTANT_APP;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f0b2329..4eec56c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8085,6 +8085,20 @@
                 "getMimeGroup not implemented in subclass");
     }
 
+    /**
+     * Grants implicit visibility of the package that provides an authority to a querying UID.
+     *
+     * @throws SecurityException when called by a package other than the contacts provider
+     * @hide
+     */
+    public void grantImplicitAccess(int queryingUid, String visibleAuthority) {
+        try {
+            ActivityThread.getPackageManager().grantImplicitAccess(queryingUid, visibleAuthority);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     // Some of the flags don't affect the query result, but let's be conservative and cache
     // each combination of flags separately.
 
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index f86eb90..8d0cc68 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -103,6 +103,7 @@
         @IntDef(flag = true, value = {
                 BIOMETRIC_STRONG,
                 BIOMETRIC_WEAK,
+                BIOMETRIC_CONVENIENCE,
                 DEVICE_CREDENTIAL,
         })
         @interface Types {}
diff --git a/core/java/android/hardware/biometrics/SensorProperties.java b/core/java/android/hardware/biometrics/SensorProperties.java
new file mode 100644
index 0000000..0f33ac4
--- /dev/null
+++ b/core/java/android/hardware/biometrics/SensorProperties.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The base class containing all sensor-agnostic information. This is a superset of the
+ * {@link android.hardware.biometrics.common.CommonProps}, and provides backwards-compatible
+ * behavior with the older generation of HIDL (non-AIDL) interfaces.
+ * @hide
+ */
+public class SensorProperties implements Parcelable {
+
+    public static final int STRENGTH_CONVENIENCE = 0;
+    public static final int STRENGTH_WEAK = 1;
+    public static final int STRENGTH_STRONG = 2;
+
+    @IntDef({STRENGTH_CONVENIENCE, STRENGTH_WEAK, STRENGTH_STRONG})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Strength {}
+
+    public final int sensorId;
+    @Strength public final int sensorStrength;
+    public final int maxEnrollmentsPerUser;
+
+    protected SensorProperties(int sensorId, @Strength int sensorStrength,
+            int maxEnrollmentsPerUser) {
+        this.sensorId = sensorId;
+        this.sensorStrength = sensorStrength;
+        this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+    }
+
+    protected SensorProperties(Parcel in) {
+        sensorId = in.readInt();
+        sensorStrength = in.readInt();
+        maxEnrollmentsPerUser = in.readInt();
+    }
+
+    public static final Creator<SensorProperties> CREATOR = new Creator<SensorProperties>() {
+        @Override
+        public SensorProperties createFromParcel(Parcel in) {
+            return new SensorProperties(in);
+        }
+
+        @Override
+        public SensorProperties[] newArray(int size) {
+            return new SensorProperties[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(sensorId);
+        dest.writeInt(sensorStrength);
+        dest.writeInt(maxEnrollmentsPerUser);
+    }
+}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8f99edf..dda1890b 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -941,6 +941,7 @@
          */
         String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default";
 
+        // TODO(b/162536543): rename it once it is proved not harmful for users.
         /**
          * Key for controlling which packages are explicitly blocked from running at refresh rates
          * higher than 60hz. An app may be added to this list if they exhibit performance issues at
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 437feb1..e744c84 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -110,5 +110,5 @@
             String opPackageName);
 
     // Give FaceService its ID. See AuthService.java
-    void initializeConfiguration(int sensorId);
+    void initializeConfiguration(int sensorId, int strength);
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index 2fd0068..718141a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -17,6 +17,7 @@
 package android.hardware.fingerprint;
 
 import android.annotation.IntDef;
+import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceSensorProperties;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -28,45 +29,44 @@
  * Container for fingerprint sensor properties.
  * @hide
  */
-public class FingerprintSensorProperties implements Parcelable {
+public class FingerprintSensorProperties extends SensorProperties {
 
     public static final int TYPE_UNKNOWN = 0;
     public static final int TYPE_REAR = 1;
-    public static final int TYPE_UDFPS = 2;
-    public static final int TYPE_POWER_BUTTON = 3;
+    public static final int TYPE_UDFPS_ULTRASONIC = 2;
+    public static final int TYPE_UDFPS_OPTICAL = 3;
+    public static final int TYPE_POWER_BUTTON = 4;
+    public static final int TYPE_HOME_BUTTON = 5;
 
-    @IntDef({
-            TYPE_UNKNOWN,
+    @IntDef({TYPE_UNKNOWN,
             TYPE_REAR,
-            TYPE_UDFPS,
-            TYPE_POWER_BUTTON})
+            TYPE_UDFPS_ULTRASONIC,
+            TYPE_UDFPS_OPTICAL,
+            TYPE_POWER_BUTTON,
+            TYPE_HOME_BUTTON})
     @Retention(RetentionPolicy.SOURCE)
     public @interface SensorType {}
 
-    public final int sensorId;
     public final @SensorType int sensorType;
     // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
     // cannot be checked
     public final boolean resetLockoutRequiresHardwareAuthToken;
-    // Maximum number of enrollments a user/profile can have.
-    public final int maxTemplatesAllowed;
 
     /**
      * Initializes SensorProperties with specified values
      */
-    public FingerprintSensorProperties(int sensorId, @SensorType int sensorType,
-            boolean resetLockoutRequiresHardwareAuthToken, int maxTemplatesAllowed) {
-        this.sensorId = sensorId;
+    public FingerprintSensorProperties(int sensorId, @Strength int strength,
+            int maxEnrollmentsPerUser, @SensorType int sensorType,
+            boolean resetLockoutRequiresHardwareAuthToken) {
+        super(sensorId, strength, maxEnrollmentsPerUser);
         this.sensorType = sensorType;
         this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
-        this.maxTemplatesAllowed = maxTemplatesAllowed;
     }
 
     protected FingerprintSensorProperties(Parcel in) {
-        sensorId = in.readInt();
+        super(in);
         sensorType = in.readInt();
         resetLockoutRequiresHardwareAuthToken = in.readBoolean();
-        maxTemplatesAllowed = in.readInt();
     }
 
     public static final Creator<FingerprintSensorProperties> CREATOR =
@@ -89,9 +89,18 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(sensorId);
+        super.writeToParcel(dest, flags);
         dest.writeInt(sensorType);
         dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
-        dest.writeInt(maxTemplatesAllowed);
+    }
+
+    public boolean isAnyUdfpsType() {
+        switch (sensorType) {
+            case TYPE_UDFPS_OPTICAL:
+            case TYPE_UDFPS_ULTRASONIC:
+                return true;
+            default:
+                return false;
+        }
     }
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 0fae156..cc2b520 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -118,7 +118,7 @@
     void removeClientActiveCallback(IFingerprintClientActiveCallback callback);
 
     // Give FingerprintService its ID. See AuthService.java
-    void initializeConfiguration(int sensorId);
+    void initializeConfiguration(int sensorId, int strength);
 
     // Notifies about a finger touching the sensor area.
     void onFingerDown(int x, int y, float minor, float major);
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index c4d123c..06b5b67 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -32,10 +32,12 @@
 import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
+import android.os.ParcelFileDescriptor;
 import android.os.SharedMemory;
 import android.system.ErrnoException;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.UUID;
@@ -109,7 +111,12 @@
         aidlModel.type = apiModel.getType();
         aidlModel.uuid = api2aidlUuid(apiModel.getUuid());
         aidlModel.vendorUuid = api2aidlUuid(apiModel.getVendorUuid());
-        aidlModel.data = byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel");
+        try {
+            aidlModel.data = ParcelFileDescriptor.dup(
+                    byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel"));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
         aidlModel.dataSize = apiModel.getData().length;
         return aidlModel;
     }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 60ddd8a..d62d1e1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -16,10 +16,10 @@
 
 package android.inputmethodservice;
 
+import static android.graphics.Color.TRANSPARENT;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowInsets.Type.navigationBars;
-import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -69,7 +69,6 @@
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.Window;
-import android.view.WindowInsets;
 import android.view.WindowInsets.Side;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
@@ -1204,25 +1203,22 @@
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
-        mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
+        mWindow.getWindow().getAttributes().setFitInsetsTypes(navigationBars());
         mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
         mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true);
 
-        // IME layout should always be inset by navigation bar, no matter its current visibility,
-        // unless automotive requests it. Automotive devices may request the navigation bar to be
-        // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard)
-        // in order to maximize the visible screen real estate. When this happens, the IME window
-        // should animate from the bottom of the screen to reduce the jank that happens from the
-        // lack of synchronization between the bottom system window and the IME window.
+        // Our window will extend into the status bar area no matter the bar is visible or not.
+        // We don't want the ColorView to be visible when status bar is shown.
+        mWindow.getWindow().setStatusBarColor(TRANSPARENT);
+
+        // Automotive devices may request the navigation bar to be hidden when the IME shows up
+        // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible
+        // screen real estate. When this happens, the IME window should animate from the bottom of
+        // the screen to reduce the jank that happens from the lack of synchronization between the
+        // bottom system window and the IME window.
         if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) {
             mWindow.getWindow().setDecorFitsSystemWindows(false);
         }
-        mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
-                (v, insets) -> v.onApplyWindowInsets(
-                        new WindowInsets.Builder(insets).setInsets(
-                                navigationBars(),
-                                insets.getInsetsIgnoringVisibility(navigationBars()))
-                                .build()));
 
         // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
         // by default (but IME developers can opt this out later if they want a new behavior).
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 1db544c..78ba7f0 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -141,8 +141,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 4b2cfe2..a2e53e2 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2551,14 +2551,16 @@
     public static native long getZramFreeKb();
 
     /**
-     * Return memory size in kilobytes allocated for ION heaps.
+     * Return memory size in kilobytes allocated for ION heaps or -1 if
+     * /sys/kernel/ion/total_heaps_kb could not be read.
      *
      * @hide
      */
     public static native long getIonHeapsSizeKb();
 
     /**
-     * Return memory size in kilobytes allocated for ION pools.
+     * Return memory size in kilobytes allocated for ION pools or -1 if
+     * /sys/kernel/ion/total_pools_kb could not be read.
      *
      * @hide
      */
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
new file mode 100644
index 0000000..e821e31
--- /dev/null
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.VibrationAttributes;
+
+/** {@hide} */
+interface IVibratorManagerService {
+    int[] getVibratorIds();
+}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 40c291f..91eb2a5 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -3,6 +3,7 @@
 per-file ExternalVibration.java = michaelwr@google.com
 per-file IExternalVibrationController.aidl = michaelwr@google.com
 per-file IExternalVibratorService.aidl = michaelwr@google.com
+per-file IVibratorManagerService.aidl = michaelwr@google.com
 per-file IVibratorService.aidl = michaelwr@google.com
 per-file NullVibrator.java = michaelwr@google.com
 per-file SystemVibrator.java = michaelwr@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 18920ca..a7055ec0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9084,6 +9084,22 @@
         };
 
         /**
+         * How long Assistant handles have enabled in milliseconds.
+         *
+         * @hide
+         */
+        public static final String ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS =
+                "reminder_exp_learning_time_elapsed";
+
+        /**
+         * How many times the Assistant has been triggered using the touch gesture.
+         *
+         * @hide
+         */
+        public static final String ASSIST_HANDLES_LEARNING_EVENT_COUNT =
+                "reminder_exp_learning_event_count";
+
+        /**
          * These entries are considered common between the personal and the managed profile,
          * since the managed profile doesn't get to change them.
          */
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 5a74ec0..b77265b 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -144,6 +144,17 @@
     }
 
     /**
+     * Adds the values in the specified array to this array.
+     */
+    public void addAll(int[] values) {
+        final int count = values.length;
+        ensureCapacity(count);
+
+        System.arraycopy(values, 0, mValues, mSize, count);
+        mSize += count;
+    }
+
+    /**
      * Ensures capacity to append at least <code>count</code> values.
      */
     private void ensureCapacity(int count) {
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index c726bee..7c01f7a8 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -130,14 +130,16 @@
         w = metrics.noncompatWidthPixels;
         metrics.noncompatWidthPixels = metrics.noncompatHeightPixels;
         metrics.noncompatHeightPixels = w;
+    }
 
-        float x = metrics.xdpi;
-        metrics.xdpi = metrics.ydpi;
-        metrics.ydpi = x;
-
-        x = metrics.noncompatXdpi;
-        metrics.noncompatXdpi = metrics.noncompatYdpi;
-        metrics.noncompatYdpi = x;
+    /** Adjusts global display metrics that is available to applications. */
+    public void adjustGlobalAppMetrics(@NonNull DisplayMetrics metrics) {
+        final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments;
+        if (rotationAdjustments == null) {
+            return;
+        }
+        metrics.noncompatWidthPixels = metrics.widthPixels = rotationAdjustments.mAppWidth;
+        metrics.noncompatHeightPixels = metrics.heightPixels = rotationAdjustments.mAppHeight;
     }
 
     /** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */
@@ -178,7 +180,7 @@
 
     /**
      * An application can be launched in different rotation than the real display. This class
-     * provides the information to adjust the values returned by {@link #Display}.
+     * provides the information to adjust the values returned by {@link Display}.
      * @hide
      */
     public static class FixedRotationAdjustments implements Parcelable {
@@ -186,12 +188,24 @@
         @Surface.Rotation
         final int mRotation;
 
+        /**
+         * The rotated {@link DisplayInfo#appWidth}. The value cannot be simply swapped according
+         * to rotation because it minus the region of screen decorations.
+         */
+        final int mAppWidth;
+
+        /** The rotated {@link DisplayInfo#appHeight}. */
+        final int mAppHeight;
+
         /** Non-null if the device has cutout. */
         @Nullable
         final DisplayCutout mRotatedDisplayCutout;
 
-        public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) {
+        public FixedRotationAdjustments(@Surface.Rotation int rotation, int appWidth, int appHeight,
+                DisplayCutout cutout) {
             mRotation = rotation;
+            mAppWidth = appWidth;
+            mAppHeight = appHeight;
             mRotatedDisplayCutout = cutout;
         }
 
@@ -199,6 +213,8 @@
         public int hashCode() {
             int hash = 17;
             hash = hash * 31 + mRotation;
+            hash = hash * 31 + mAppWidth;
+            hash = hash * 31 + mAppHeight;
             hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout);
             return hash;
         }
@@ -210,12 +226,14 @@
             }
             final FixedRotationAdjustments other = (FixedRotationAdjustments) o;
             return mRotation == other.mRotation
+                    && mAppWidth == other.mAppWidth && mAppHeight == other.mAppHeight
                     && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout);
         }
 
         @Override
         public String toString() {
             return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation)
+                    + " appWidth=" + mAppWidth + " appHeight=" + mAppHeight
                     + " cutout=" + mRotatedDisplayCutout + "}";
         }
 
@@ -227,12 +245,16 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mRotation);
+            dest.writeInt(mAppWidth);
+            dest.writeInt(mAppHeight);
             dest.writeTypedObject(
                     new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags);
         }
 
         private FixedRotationAdjustments(Parcel in) {
             mRotation = in.readInt();
+            mAppWidth = in.readInt();
+            mAppHeight = in.readInt();
             final DisplayCutout.ParcelableWrapper cutoutWrapper =
                     in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR);
             mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null;
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index f462a99..5f8b5e5 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -76,6 +76,10 @@
             ITYPE_BOTTOM_GESTURES,
             ITYPE_LEFT_GESTURES,
             ITYPE_RIGHT_GESTURES,
+            ITYPE_TOP_MANDATORY_GESTURES,
+            ITYPE_BOTTOM_MANDATORY_GESTURES,
+            ITYPE_LEFT_MANDATORY_GESTURES,
+            ITYPE_RIGHT_MANDATORY_GESTURES,
             ITYPE_TOP_TAPPABLE_ELEMENT,
             ITYPE_BOTTOM_TAPPABLE_ELEMENT,
             ITYPE_LEFT_DISPLAY_CUTOUT,
@@ -104,20 +108,27 @@
     public static final int ITYPE_BOTTOM_GESTURES = 4;
     public static final int ITYPE_LEFT_GESTURES = 5;
     public static final int ITYPE_RIGHT_GESTURES = 6;
-    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 7;
-    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 8;
 
-    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 9;
-    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 10;
-    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 11;
-    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 12;
+    /** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */
+    public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
+    public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
+    public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
+    public static final int ITYPE_RIGHT_MANDATORY_GESTURES = 10;
+
+    public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 11;
+    public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 12;
+
+    public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 13;
+    public static final int ITYPE_TOP_DISPLAY_CUTOUT = 14;
+    public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 15;
+    public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 16;
 
     /** Input method window. */
-    public static final int ITYPE_IME = 13;
+    public static final int ITYPE_IME = 17;
 
     /** Additional system decorations inset type. */
-    public static final int ITYPE_CLIMATE_BAR = 14;
-    public static final int ITYPE_EXTRA_NAVIGATION_BAR = 15;
+    public static final int ITYPE_CLIMATE_BAR = 18;
+    public static final int ITYPE_EXTRA_NAVIGATION_BAR = 19;
 
     static final int LAST_TYPE = ITYPE_EXTRA_NAVIGATION_BAR;
     public static final int SIZE = LAST_TYPE + 1;
@@ -485,6 +496,10 @@
                 return Type.IME;
             case ITYPE_TOP_GESTURES:
             case ITYPE_BOTTOM_GESTURES:
+            case ITYPE_TOP_MANDATORY_GESTURES:
+            case ITYPE_BOTTOM_MANDATORY_GESTURES:
+            case ITYPE_LEFT_MANDATORY_GESTURES:
+            case ITYPE_RIGHT_MANDATORY_GESTURES:
                 return Type.MANDATORY_SYSTEM_GESTURES;
             case ITYPE_LEFT_GESTURES:
             case ITYPE_RIGHT_GESTURES:
@@ -544,6 +559,14 @@
                 return "ITYPE_LEFT_GESTURES";
             case ITYPE_RIGHT_GESTURES:
                 return "ITYPE_RIGHT_GESTURES";
+            case ITYPE_TOP_MANDATORY_GESTURES:
+                return "ITYPE_TOP_MANDATORY_GESTURES";
+            case ITYPE_BOTTOM_MANDATORY_GESTURES:
+                return "ITYPE_BOTTOM_MANDATORY_GESTURES";
+            case ITYPE_LEFT_MANDATORY_GESTURES:
+                return "ITYPE_LEFT_MANDATORY_GESTURES";
+            case ITYPE_RIGHT_MANDATORY_GESTURES:
+                return "ITYPE_RIGHT_MANDATORY_GESTURES";
             case ITYPE_TOP_TAPPABLE_ELEMENT:
                 return "ITYPE_TOP_TAPPABLE_ELEMENT";
             case ITYPE_BOTTOM_TAPPABLE_ELEMENT:
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d55c25f..c698b92 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -316,11 +316,19 @@
     public static final int HIDDEN = 0x00000004;
 
     /**
-     * Surface creation flag: The surface contains secure content, special
-     * measures will be taken to disallow the surface's content to be copied
-     * from another process. In particular, screenshots and VNC servers will
-     * be disabled, but other measures can take place, for instance the
-     * surface might not be hardware accelerated.
+     * Surface creation flag: Skip this layer and its children when taking a screenshot. This
+     * also includes mirroring and screen recording, so the layers with flag SKIP_SCREENSHOT
+     * will not be included on non primary displays.
+     * @hide
+     */
+    public static final int SKIP_SCREENSHOT = 0x00000040;
+
+    /**
+     * Surface creation flag: Special measures will be taken to disallow the surface's content to
+     * be copied. In particular, screenshots and secondary, non-secure displays will render black
+     * content instead of the surface content.
+     *
+     * @see #createDisplay(String, boolean)
      * @hide
      */
     public static final int SECURE = 0x00000080;
@@ -482,15 +490,6 @@
     public static final int POWER_MODE_ON_SUSPEND = 4;
 
     /**
-     * A value for windowType used to indicate that the window should be omitted from screenshots
-     * and display mirroring. A temporary workaround until we express such things with
-     * the hierarchy.
-     * TODO: b/64227542
-     * @hide
-     */
-    public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;
-
-    /**
      * internal representation of how to interpret pixel value, used only to convert to ColorSpace.
      */
     private static final int INTERNAL_DATASPACE_SRGB = 142671872;
@@ -3287,6 +3286,22 @@
             return this;
         }
 
+        /**
+         * Adds or removes the flag SKIP_SCREENSHOT of the surface.  Setting the flag is equivalent
+         * to creating the Surface with the {@link #SKIP_SCREENSHOT} flag.
+         *
+         * @hide
+         */
+        public Transaction setSkipScreenshot(SurfaceControl sc, boolean skipScrenshot) {
+            checkPreconditions(sc);
+            if (skipScrenshot) {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, SKIP_SCREENSHOT, SKIP_SCREENSHOT);
+            } else {
+                nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SKIP_SCREENSHOT);
+            }
+            return this;
+        }
+
          /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b644e9e..abda698 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -420,8 +420,6 @@
                 final boolean useBLAST = viewRoot.useBLAST();
                 viewRoot.registerRtFrameCallback(frame -> {
                     try {
-                        final SurfaceControl.Transaction t = useBLAST ?
-                            viewRoot.getBLASTSyncTransaction() : new SurfaceControl.Transaction();
                         synchronized (mSurfaceControlLock) {
                             if (!parent.isValid()) {
                                 if (DEBUG) {
@@ -443,16 +441,22 @@
                                 Log.d(TAG, System.identityHashCode(this)
                                         + " updateSurfaceAlpha RT: set alpha=" + alpha);
                             }
-                            t.setAlpha(mSurfaceControl, alpha);
-                            if (!useBLAST) {
+                            if (useBLAST) {
+                                synchronized (viewRoot.getBlastTransactionLock()) {
+                                    viewRoot.getBLASTSyncTransaction()
+                                            .setAlpha(mSurfaceControl, alpha);
+                                }
+                            } else {
+                                Transaction t = new SurfaceControl.Transaction();
+                                t.setAlpha(mSurfaceControl, alpha);
                                 t.deferTransactionUntil(mSurfaceControl,
                                         viewRoot.getRenderSurfaceControl(), frame);
+                                t.apply();
                             }
                         }
                         // It's possible that mSurfaceControl is released in the UI thread before
                         // the transaction completes. If that happens, an exception is thrown, which
                         // must be caught immediately.
-                        t.apply();
                     } catch (Exception e) {
                         Log.e(TAG, System.identityHashCode(this)
                                 + "updateSurfaceAlpha RT: Exception during surface transaction", e);
@@ -793,23 +797,26 @@
         final boolean useBLAST = viewRoot.useBLAST();
         viewRoot.registerRtFrameCallback(frame -> {
             try {
-                final SurfaceControl.Transaction t = useBLAST
-                        ? viewRoot.getBLASTSyncTransaction()
-                        : new SurfaceControl.Transaction();
                 synchronized (mSurfaceControlLock) {
                     if (!parent.isValid() || mSurfaceControl == null) {
                         return;
                     }
-                    updateRelativeZ(t);
-                    if (!useBLAST) {
+
+                    if (useBLAST) {
+                        synchronized (viewRoot.getBlastTransactionLock()) {
+                            updateRelativeZ(viewRoot.getBLASTSyncTransaction());
+                        }
+                    } else {
+                        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+                        updateRelativeZ(t);
                         t.deferTransactionUntil(mSurfaceControl,
                                 viewRoot.getRenderSurfaceControl(), frame);
+                        t.apply();
                     }
                 }
                 // It's possible that mSurfaceControl is released in the UI thread before
                 // the transaction completes. If that happens, an exception is thrown, which
                 // must be caught immediately.
-                t.apply();
              } catch (Exception e) {
                 Log.e(TAG, System.identityHashCode(this)
                         + "setZOrderOnTop RT: Exception during surface transaction", e);
@@ -1252,7 +1259,7 @@
     private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
             Rect position, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
-        if (frameNumber > 0 && viewRoot != null && !viewRoot.isDrawingToBLASTTransaction()) {
+        if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) {
             t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
                     frameNumber);
         }
@@ -1277,19 +1284,23 @@
         return mRTLastReportedPosition;
     }
 
+    private void setParentSpaceRectangle(Transaction t, Rect position, long frameNumber) {
+        final ViewRootImpl viewRoot = getViewRootImpl();
+        applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
+        applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
+    }
+
     private void setParentSpaceRectangle(Rect position, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
-        final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction();
-        final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() :
-            mRtTransaction;
+        final boolean useBLAST = viewRoot.useBLAST();
 
-        applySurfaceTransforms(mSurfaceControl, t, position, frameNumber);
-
-        applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface,
-                frameNumber);
-
-        if (!useBLAST) {
-            t.apply();
+        if (useBLAST) {
+            synchronized (viewRoot.getBlastTransactionLock()) {
+                setParentSpaceRectangle(viewRoot.getBLASTSyncTransaction(), position, frameNumber);
+            }
+        } else {
+            setParentSpaceRectangle(mRtTransaction, position, frameNumber);
+            mRtTransaction.apply();
         }
     }
 
@@ -1337,10 +1348,20 @@
             }
         }
 
+        private void releaseSurfaces(Transaction t) {
+            if (mRtReleaseSurfaces) {
+                mRtReleaseSurfaces = false;
+                t.remove(mSurfaceControl);
+                t.remove(mBackgroundControl);
+                mSurfaceControl = null;
+                mBackgroundControl = null;
+            }
+        }
+
         @Override
         public void positionLost(long frameNumber) {
             final ViewRootImpl viewRoot = getViewRootImpl();
-            boolean useBLAST = viewRoot != null && viewRoot.isDrawingToBLASTTransaction();
+            boolean useBLAST = viewRoot != null && viewRoot.useBLAST();
             if (DEBUG) {
                 Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
                         System.identityHashCode(this), frameNumber));
@@ -1351,38 +1372,31 @@
                 return;
             }
 
-            final SurfaceControl.Transaction t = useBLAST ?
-                (viewRoot != null ? viewRoot.getBLASTSyncTransaction() : mRtTransaction) :
-                mRtTransaction;
-
             /**
              * positionLost can be called while UI thread is un-paused so we
              * need to hold the lock here.
              */
             synchronized (mSurfaceControlLock) {
-                if (frameNumber > 0 && viewRoot !=  null && !useBLAST) {
-                    if (viewRoot.mSurface.isValid()) {
+                if (useBLAST) {
+                    synchronized (viewRoot.getBlastTransactionLock()) {
+                        viewRoot.getBLASTSyncTransaction().hide(mSurfaceControl);
+                        releaseSurfaces(viewRoot.getBLASTSyncTransaction());
+                    }
+                } else {
+                    if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) {
                         mRtTransaction.deferTransactionUntil(mSurfaceControl,
                                 viewRoot.getRenderSurfaceControl(), frameNumber);
                     }
-                }
-                t.hide(mSurfaceControl);
-
-                if (mRtReleaseSurfaces) {
-                    mRtReleaseSurfaces = false;
-                    mRtTransaction.remove(mSurfaceControl);
-                    mRtTransaction.remove(mBackgroundControl);
-                    mSurfaceControl = null;
-                    mBackgroundControl = null;
+                    mRtTransaction.hide(mSurfaceControl);
+                    releaseSurfaces(mRtTransaction);
+                    // If we aren't using BLAST, we apply the transaction locally, otherwise we let
+                    // the ViewRoot apply it for us.
+                    // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to
+                    // apply the transaction.
+                    mRtTransaction.apply();
                 }
                 mRtHandlingPositionUpdates = false;
             }
-
-            // If we aren't using BLAST, we apply the transaction locally, otherise we let the ViewRoot apply it for us.
-            // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to apply the transaction.
-            if (!useBLAST || viewRoot == null) {
-                mRtTransaction.apply();
-            }
         }
     };
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0bbd899..d6cf0c4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -654,26 +654,25 @@
         int localChanges;
     }
 
-    // If set, ViewRootImpl will call BLASTBufferQueue::setNextTransaction with
-    // mRtBLASTSyncTransaction, prior to invoking draw. This provides a way
-    // to redirect the buffers in to transactions.
+    // If set, ViewRootImpl will request a callback from HWRender when it's ready to render the next
+    // frame. This will allow VRI to call BLASTBufferQueue::setNextTransaction with
+    // mRtBLASTSyncTransaction, so the next frame submitted will be added to the
+    // mRtBLASTSyncTransaction instead of getting applied.
     private boolean mNextDrawUseBLASTSyncTransaction;
-    // Set when calling setNextTransaction, we can't just reuse mNextDrawUseBLASTSyncTransaction
-    // because, imagine this scenario:
-    //     1. First draw is using BLAST, mNextDrawUseBLAST = true
-    //     2. We call perform draw and are waiting on the callback
-    //     3. After the first perform draw but before the first callback and the
-    //        second perform draw, a second draw sets mNextDrawUseBLAST = true (it already was)
-    //     4. At this point the callback fires and we set mNextDrawUseBLAST = false;
-    //     5. We get to performDraw and fail to sync as we intended because mNextDrawUseBLAST
-    //        is now false.
-    // This is why we use a two-step latch with the two booleans, one consumed from
-    // performDraw and one consumed from finishBLASTSync()
-    private boolean mNextReportConsumeBLAST;
-    // Be very careful with the threading here. This is used from the render thread while
-    // the UI thread is paused and then applied and cleared from the UI thread right after
-    // draw returns.
-    private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction();
+
+    // This is used to signal if the mRtBLASTSyncTransaction should be applied/merged. When true,
+    // it indicates mRtBLASTSyncTransaction was sent to BLASTBufferQueue::setNextTransaction.
+    // Therefore, in onFrameComplete, if mRtNextFrameReportConsumeWithBlast is true, that means
+    // mRtBLASTSyncTransaction now contains the next buffer frame to be applied.
+    private boolean mRtNextFrameReportedConsumeWithBlast;
+
+    // Be very careful with the threading here. This is used from a thread pool generated by the
+    // render thread. Therefore, it needs to be locked when updating from the thread pool since
+    // multiple threads can be accessing it. It does not need to be locked when applied or merged
+    // since that can only happen from the frame complete callback after the other callbacks have
+    // been invoked.
+    private final SurfaceControl.Transaction mRtBLASTSyncTransaction =
+            new SurfaceControl.Transaction();
 
     // Keeps track of whether the WM requested us to use BLAST Sync when calling relayout.
     //  We use this to make sure we don't send the WM transactions from an internal BLAST sync
@@ -1986,11 +1985,7 @@
             mCompatibleVisibilityInfo.globalVisibility =
                     (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE)
                             | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
-            if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) {
-                mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
-                mHandler.sendMessage(mHandler.obtainMessage(
-                        MSG_DISPATCH_SYSTEM_UI_VISIBILITY, mCompatibleVisibilityInfo));
-            }
+            dispatchDispatchSystemUiVisibilityChanged(mCompatibleVisibilityInfo);
             if (mAttachInfo.mKeepScreenOn != oldScreenOn
                     || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility
                     || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) {
@@ -2043,9 +2038,30 @@
             info.globalVisibility |= systemUiFlag;
             info.localChanges &= ~systemUiFlag;
         }
-        if (mDispatchedSystemUiVisibility != info.globalVisibility) {
+        dispatchDispatchSystemUiVisibilityChanged(info);
+    }
+
+    /**
+     * If the system is forcing showing any system bar, the legacy low profile flag should be
+     * cleared for compatibility.
+     *
+     * @param showTypes {@link InsetsType types} shown by the system.
+     * @param fromIme {@code true} if the invocation is from IME.
+     */
+    private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) {
+        final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo;
+        if ((showTypes & Type.systemBars()) != 0 && !fromIme
+                && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+            info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE;
+            info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE;
+            dispatchDispatchSystemUiVisibilityChanged(info);
+        }
+    }
+
+    private void dispatchDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) {
+        if (mDispatchedSystemUiVisibility != args.globalVisibility) {
             mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY);
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, info));
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
         }
     }
 
@@ -3783,26 +3799,29 @@
                                     commitCallbacks.get(i).run();
                                 }
                             }
-                        });});
+                        });
+                });
             }
         }
 
         try {
             if (mNextDrawUseBLASTSyncTransaction) {
-                // TODO(b/149747443)
-                // We aren't prepared to handle overlapping use of mRtBLASTSyncTransaction
-                // so if we are BLAST syncing we make sure the previous draw has
-                // totally finished.
-                if (mAttachInfo.mThreadedRenderer != null) {
-                    mAttachInfo.mThreadedRenderer.pause();
-                }
-
-                mNextReportConsumeBLAST = true;
+                // Frame callbacks will always occur after submitting draw requests and before
+                // the draw actually occurs. This will ensure that we set the next transaction
+                // for the frame that's about to get drawn and not on a previous frame that.
+                //
+                // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
+                // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
+                // next frame completed should be reported with the blast sync transaction.
+                registerRtFrameCallback(frame -> {
+                    mRtNextFrameReportedConsumeWithBlast = true;
+                    if (mBlastBufferQueue != null) {
+                        // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
+                        // being modified and only sent to BlastBufferQueue.
+                        mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
+                    }
+                });
                 mNextDrawUseBLASTSyncTransaction = false;
-
-                if (mBlastBufferQueue != null) {
-                    mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
-                }
             }
             boolean canUseAsync = draw(fullRedrawNeeded);
             if (usingAsyncReport && !canUseAsync) {
@@ -4950,6 +4969,7 @@
                                 String.format("Calling showInsets(%d,%b) on window that no longer"
                                         + " has views.", msg.arg1, msg.arg2 == 1));
                     }
+                    clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1);
                     mInsetsController.show(msg.arg1, msg.arg2 == 1);
                     break;
                 }
@@ -9757,9 +9777,12 @@
 
     private void finishBLASTSync(boolean apply) {
         mSendNextFrameToWm = false;
-        if (mNextReportConsumeBLAST) {
-            mNextReportConsumeBLAST = false;
+        if (mRtNextFrameReportedConsumeWithBlast) {
+            mRtNextFrameReportedConsumeWithBlast = false;
 
+            // We don't need to synchronize mRtBLASTSyncTransaction here we're guaranteed that this
+            // is called after all onFrameDraw and after callbacks to PositionUpdateListener.
+            // Therefore, no one should be modifying this object until the next vsync.
             if (apply) {
                 mRtBLASTSyncTransaction.apply();
             } else {
@@ -9772,6 +9795,10 @@
         return mRtBLASTSyncTransaction;
     }
 
+    Object getBlastTransactionLock() {
+        return mRtBLASTSyncTransaction;
+    }
+
     /**
      * @hide
      */
@@ -9799,12 +9826,4 @@
     boolean useBLAST() {
         return mUseBLASTAdapter && !mForceDisableBLAST;
     }
-
-    /**
-     * Returns true if we are about to or currently processing a draw directed
-     * in to a BLAST transaction.
-     */
-    boolean isDrawingToBLASTTransaction() {
-        return mNextReportConsumeBLAST;
-    }
 }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 8be37e9..ba90154 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -238,6 +238,22 @@
     }
 
     /**
+     * Sets whether a container should ignore the orientation request from apps below it. It
+     * currently only applies to {@link com.android.server.wm.TaskDisplayArea}. When {@code false},
+     * it may rotate based on the orientation request; When {@code true}, it can never specify
+     * orientation, but shows the fixed-orientation apps in the letterbox.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setIgnoreOrientationRequest(
+            @NonNull WindowContainerToken container, boolean ignoreOrientationRequest) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mIgnoreOrientationRequest = ignoreOrientationRequest;
+        chg.mChangeMask |= Change.CHANGE_IGNORE_ORIENTATION_REQUEST;
+        return this;
+    }
+
+    /**
      * Reparents a container into another one. The effect of a {@code null} parent can vary. For
      * example, reparenting a stack to {@code null} will reparent it to its display.
      *
@@ -341,10 +357,12 @@
         public static final int CHANGE_PIP_CALLBACK = 1 << 2;
         public static final int CHANGE_HIDDEN = 1 << 3;
         public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4;
+        public static final int CHANGE_IGNORE_ORIENTATION_REQUEST = 1 << 5;
 
         private final Configuration mConfiguration = new Configuration();
         private boolean mFocusable = true;
         private boolean mHidden = false;
+        private boolean mIgnoreOrientationRequest = false;
         private int mChangeMask = 0;
         private @ActivityInfo.Config int mConfigSetMask = 0;
         private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
@@ -362,6 +380,7 @@
             mConfiguration.readFromParcel(in);
             mFocusable = in.readBoolean();
             mHidden = in.readBoolean();
+            mIgnoreOrientationRequest = in.readBoolean();
             mChangeMask = in.readInt();
             mConfigSetMask = in.readInt();
             mWindowSetMask = in.readInt();
@@ -404,6 +423,9 @@
             if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
                 mHidden = other.mHidden;
             }
+            if ((other.mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
+                mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
+            }
             mChangeMask |= other.mChangeMask;
             if (other.mActivityWindowingMode >= 0) {
                 mActivityWindowingMode = other.mActivityWindowingMode;
@@ -445,6 +467,15 @@
             return mHidden;
         }
 
+        /** Gets the requested state of whether to ignore orientation request. */
+        public boolean getIgnoreOrientationRequest() {
+            if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) == 0) {
+                throw new RuntimeException("IgnoreOrientationRequest not set. "
+                        + "Check CHANGE_IGNORE_ORIENTATION_REQUEST first");
+            }
+            return mIgnoreOrientationRequest;
+        }
+
         public int getChangeMask() {
             return mChangeMask;
         }
@@ -509,6 +540,9 @@
             if (mBoundsChangeTransaction != null) {
                 sb.append("hasBoundsTransaction,");
             }
+            if ((mChangeMask & CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
+                sb.append("ignoreOrientationRequest:" + mIgnoreOrientationRequest + ",");
+            }
             sb.append("}");
             return sb.toString();
         }
@@ -518,6 +552,7 @@
             mConfiguration.writeToParcel(dest, flags);
             dest.writeBoolean(mFocusable);
             dest.writeBoolean(mHidden);
+            dest.writeBoolean(mIgnoreOrientationRequest);
             dest.writeInt(mChangeMask);
             dest.writeInt(mConfigSetMask);
             dest.writeInt(mWindowSetMask);
diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java
index f08d0ef8..6b8cf63 100644
--- a/core/java/com/android/internal/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/BrightnessSynchronizer.java
@@ -36,7 +36,7 @@
  * (new) system for storing the brightness. It has methods to convert between the two and also
  * observes for when one of the settings is changed and syncs this with the other.
  */
-public class BrightnessSynchronizer{
+public class BrightnessSynchronizer {
 
     private static final int MSG_UPDATE_FLOAT = 1;
     private static final int MSG_UPDATE_INT = 2;
@@ -78,6 +78,26 @@
         mContext = context;
         mBrightnessSyncObserver = new BrightnessSyncObserver(mHandler);
         mBrightnessSyncObserver.startObserving();
+
+        // It is possible for the system to start up with the int and float values not
+        // synchronized. So we force an update to the int value, since float is the source
+        // of truth. Fallback to int value, if float is invalid. If both are invalid, use default
+        // float value from config.
+        final float currentFloatBrightness = getScreenBrightnessFloat(context);
+        final int currentIntBrightness = getScreenBrightnessInt(context);
+
+        if (!Float.isNaN(currentFloatBrightness)) {
+            updateBrightnessIntFromFloat(currentFloatBrightness);
+        } else if (currentIntBrightness != -1) {
+            updateBrightnessFloatFromInt(currentIntBrightness);
+        } else {
+            final float defaultBrightness = mContext.getResources().getFloat(
+                    com.android.internal.R.dimen.config_screenBrightnessSettingDefaultFloat);
+            Settings.System.putFloatForUser(mContext.getContentResolver(),
+                    Settings.System.SCREEN_BRIGHTNESS_FLOAT, defaultBrightness,
+                    UserHandle.USER_CURRENT);
+
+        }
     }
 
     /**
@@ -132,7 +152,8 @@
 
     private static int getScreenBrightnessInt(Context context) {
         return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS, 0, UserHandle.USER_CURRENT);
+                Settings.System.SCREEN_BRIGHTNESS, PowerManager.BRIGHTNESS_INVALID,
+                UserHandle.USER_CURRENT);
     }
 
     private float mPreferredSettingValue;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5910b33..944f2ec 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -274,8 +274,6 @@
     private int mLastNumberOfChildren = -1;
 
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
-    // TODO: Update to handle landscape instead of using static value
-    private static final int MAX_RANKED_TARGETS = 4;
 
     private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
     private final Set<Pair<ComponentName, UserHandle>> mServicesRequested = new HashSet<>();
@@ -952,7 +950,7 @@
         updateStickyContentPreview();
         if (shouldShowStickyContentPreview()
                 || mChooserMultiProfilePagerAdapter
-                        .getCurrentRootAdapter().getContentPreviewRowCount() != 0) {
+                        .getCurrentRootAdapter().getSystemRowCount() != 0) {
             logActionShareWithPreview();
         }
         return postRebuildListInternal(rebuildCompleted);
@@ -1326,13 +1324,14 @@
             ViewGroup parent) {
         ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
                 R.layout.chooser_grid_preview_image, parent, false);
+        ViewGroup imagePreview = contentPreviewLayout.findViewById(R.id.content_preview_image_area);
 
         final ViewGroup actionRow =
                 (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
         //TODO: addActionButton(actionRow, createCopyButton());
         addActionButton(actionRow, createNearbyButton(targetIntent));
 
-        mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true);
+        mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false);
 
         String action = targetIntent.getAction();
         if (Intent.ACTION_SEND.equals(action)) {
@@ -1352,7 +1351,7 @@
             if (imageUris.size() == 0) {
                 Log.i(TAG, "Attempted to display image preview area with zero"
                         + " available images detected in EXTRA_STREAM list");
-                contentPreviewLayout.setVisibility(View.GONE);
+                imagePreview.setVisibility(View.GONE);
                 return contentPreviewLayout;
             }
 
@@ -2695,7 +2694,7 @@
                 final int bottomInset = mSystemWindowInsets != null
                                             ? mSystemWindowInsets.bottom : 0;
                 int offset = bottomInset;
-                int rowsToShow = gridAdapter.getContentPreviewRowCount()
+                int rowsToShow = gridAdapter.getSystemRowCount()
                         + gridAdapter.getProfileRowCount()
                         + gridAdapter.getServiceTargetRowCount()
                         + gridAdapter.getCallerAndRankedTargetRowCount();
@@ -3295,7 +3294,7 @@
 
         public int getRowCount() {
             return (int) (
-                    getContentPreviewRowCount()
+                    getSystemRowCount()
                             + getProfileRowCount()
                             + getServiceTargetRowCount()
                             + getCallerAndRankedTargetRowCount()
@@ -3307,22 +3306,21 @@
         }
 
         /**
-         * Returns either {@code 0} or {@code 1} depending on whether we want to show the list item
-         * content preview. Not to be confused with the sticky content preview which is above the
-         * personal and work tabs.
+         * Whether the "system" row of targets is displayed.
+         * This area includes the content preview (if present) and action row.
          */
-        public int getContentPreviewRowCount() {
+        public int getSystemRowCount() {
             // For the tabbed case we show the sticky content preview above the tabs,
             // please refer to shouldShowStickyContentPreview
             if (shouldShowTabs()) {
                 return 0;
             }
+
             if (!isSendAction(getTargetIntent())) {
                 return 0;
             }
 
-            if (mHideContentPreview || mChooserListAdapter == null
-                    || mChooserListAdapter.getCount() == 0) {
+            if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) {
                 return 0;
             }
 
@@ -3364,7 +3362,7 @@
         @Override
         public int getItemCount() {
             return (int) (
-                    getContentPreviewRowCount()
+                    getSystemRowCount()
                             + getProfileRowCount()
                             + getServiceTargetRowCount()
                             + getCallerAndRankedTargetRowCount()
@@ -3419,7 +3417,7 @@
         public int getItemViewType(int position) {
             int count;
 
-            int countSum = (count = getContentPreviewRowCount());
+            int countSum = (count = getSystemRowCount());
             if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW;
 
             countSum += (count = getProfileRowCount());
@@ -3643,7 +3641,7 @@
         }
 
         int getListPosition(int position) {
-            position -= getContentPreviewRowCount() + getProfileRowCount();
+            position -= getSystemRowCount() + getProfileRowCount();
 
             final int serviceCount = mChooserListAdapter.getServiceTargetCount();
             final int serviceRows = (int) Math.ceil((float) serviceCount
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index dd1978e..85dc2ae 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -24,11 +24,11 @@
 import android.view.FrameMetrics;
 import android.view.ThreadedRenderer;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor.Session;
 import com.android.internal.util.FrameworkStatsLog;
 
 /**
+ * A class that allows the app to get the frame metrics from HardwareRendererObserver.
  * @hide
  */
 public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
@@ -45,28 +45,21 @@
     private long mBeginTime = UNKNOWN_TIMESTAMP;
     private long mEndTime = UNKNOWN_TIMESTAMP;
     private boolean mShouldTriggerTrace;
+    private boolean mSessionEnd;
     private int mTotalFramesCount = 0;
     private int mMissedFramesCount = 0;
     private long mMaxFrameTimeNanos = 0;
 
     private Session mSession;
 
-    public FrameTracker(@NonNull Session session,
-            @NonNull Handler handler, @NonNull ThreadedRenderer renderer) {
-        mSession = session;
-        mRendererWrapper = new ThreadedRendererWrapper(renderer);
-        mMetricsWrapper = new FrameMetricsWrapper();
-        mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
-    }
-
     /**
-     * This constructor is only for unit tests.
+     * Constructor of FrameTracker.
      * @param session a trace session.
-     * @param renderer a test double for ThreadedRenderer
-     * @param metrics a test double for FrameMetrics
+     * @param handler a handler for handling callbacks.
+     * @param renderer a ThreadedRendererWrapper instance.
+     * @param metrics a FrameMetricsWrapper instance.
      */
-    @VisibleForTesting
-    public FrameTracker(@NonNull Session session, Handler handler,
+    public FrameTracker(@NonNull Session session, @NonNull Handler handler,
             @NonNull ThreadedRendererWrapper renderer, @NonNull FrameMetricsWrapper metrics) {
         mSession = session;
         mRendererWrapper = renderer;
@@ -77,15 +70,11 @@
     /**
      * Begin a trace session of the CUJ.
      */
-    public void begin() {
+    public synchronized void begin() {
         long timestamp = System.nanoTime();
         if (DEBUG) {
             Log.d(TAG, "begin: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
-                    + ", end(ns)=" + mEndTime + ", session=" + mSession);
-        }
-        if (mBeginTime != UNKNOWN_TIMESTAMP && mEndTime == UNKNOWN_TIMESTAMP) {
-            // We have an ongoing tracing already, skip subsequent calls.
-            return;
+                    + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
         }
         mBeginTime = timestamp;
         mEndTime = UNKNOWN_TIMESTAMP;
@@ -96,32 +85,48 @@
     /**
      * End the trace session of the CUJ.
      */
-    public void end() {
+    public synchronized void end() {
         long timestamp = System.nanoTime();
         if (DEBUG) {
             Log.d(TAG, "end: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
-                    + ", end(ns)=" + mEndTime + ", session=" + mSession);
-        }
-        if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) {
-            // We haven't started a trace yet.
-            return;
+                    + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
         }
         mEndTime = timestamp;
         Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
+        // We don't remove observer here,
+        // will remove it when all the frame metrics in this duration are called back.
+        // See onFrameMetricsAvailable for the logic of removing the observer.
+    }
+
+    /**
+     * Cancel the trace session of the CUJ.
+     */
+    public synchronized void cancel() {
+        if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) return;
+        if (DEBUG) {
+            Log.d(TAG, "cancel: time(ns)=" + System.nanoTime() + ", begin(ns)=" + mBeginTime
+                    + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
+        }
+        Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
+        mRendererWrapper.removeObserver(mObserver);
+        mBeginTime = UNKNOWN_TIMESTAMP;
+        mEndTime = UNKNOWN_TIMESTAMP;
+        mShouldTriggerTrace = false;
     }
 
     @Override
-    public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+    public synchronized void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
         // Since this callback might come a little bit late after the end() call.
         // We should keep tracking the begin / end timestamp.
         // Then compare with vsync timestamp to check if the frame is in the duration of the CUJ.
 
-        if (mBeginTime == UNKNOWN_TIMESTAMP) return; // We haven't started tracing yet.
         long vsyncTimestamp = mMetricsWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP);
-        if (vsyncTimestamp < mBeginTime) return; // The tracing has been started.
+        // Discard the frame metrics which is not in the trace session.
+        if (vsyncTimestamp < mBeginTime) return;
 
-        // If the end time has not been set, we are still in the tracing.
-        if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime) {
+        // We stop getting callback when the vsync is later than the end calls.
+        if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime && !mSessionEnd) {
+            mSessionEnd = true;
             // The tracing has been ended, remove the observer, see if need to trigger perfetto.
             mRendererWrapper.removeObserver(mObserver);
 
@@ -170,9 +175,8 @@
     /**
      * Trigger the prefetto daemon.
      */
-    @VisibleForTesting
     public void triggerPerfetto() {
-        InteractionJankMonitor.trigger();
+        InteractionJankMonitor.getInstance().trigger();
     }
 
     /**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 5a0cbf9..19dc2ed 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -21,15 +21,17 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.os.HandlerThread;
-import android.view.ThreadedRenderer;
+import android.util.Log;
+import android.util.SparseArray;
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * This class let users to begin and end the always on tracing mechanism.
@@ -38,11 +40,17 @@
 public class InteractionJankMonitor {
     private static final String TAG = InteractionJankMonitor.class.getSimpleName();
     private static final boolean DEBUG = false;
-    private static final Object LOCK = new Object();
+    private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
+    private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
 
     // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
-    public static final int CUJ_NOTIFICATION_SHADE_MOTION = 0;
-    public static final int CUJ_NOTIFICATION_SHADE_GESTURE = 1;
+    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 1;
+    public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 0;
+    public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 0;
 
     private static final int NO_STATSD_LOGGING = -1;
 
@@ -53,141 +61,255 @@
             UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
     };
 
-    private static ThreadedRenderer sRenderer;
-    private static Map<String, FrameTracker> sRunningTracker;
-    private static HandlerThread sWorker;
-    private static boolean sInitialized;
+    private static volatile InteractionJankMonitor sInstance;
+
+    private ThreadedRendererWrapper mRenderer;
+    private FrameMetricsWrapper mMetrics;
+    private SparseArray<FrameTracker> mRunningTrackers;
+    private SparseArray<Runnable> mTimeoutActions;
+    private HandlerThread mWorker;
+    private boolean mInitialized;
 
     /** @hide */
     @IntDef({
-            CUJ_NOTIFICATION_SHADE_MOTION,
-            CUJ_NOTIFICATION_SHADE_GESTURE
+            CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
+            CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK,
+            CUJ_NOTIFICATION_SHADE_SCROLL_FLING,
+            CUJ_NOTIFICATION_SHADE_ROW_EXPAND,
+            CUJ_NOTIFICATION_SHADE_ROW_SWIPE,
+            CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
+            CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {}
 
     /**
-     * @param view Any view in the view tree to get context and ThreadedRenderer.
+     * Get the singleton of InteractionJankMonitor.
+     * @return instance of InteractionJankMonitor
      */
-    public static void init(@NonNull View view) {
-        init(view, null, null, null);
-    }
-
-    /**
-     * Should be only invoked internally or from unit tests.
-     */
-    @VisibleForTesting
-    public static void init(@NonNull View view, @NonNull ThreadedRenderer renderer,
-            @NonNull Map<String, FrameTracker> map, @NonNull HandlerThread worker) {
-        //TODO (163505250): This should be no-op if not in droid food rom.
-        synchronized (LOCK) {
-            if (!sInitialized) {
-                if (!view.isAttachedToWindow()) {
-                    throw new IllegalStateException("View is not attached!");
+    public static InteractionJankMonitor getInstance() {
+        // Use DCL here since this method might be invoked very often.
+        if (sInstance == null) {
+            synchronized (InteractionJankMonitor.class) {
+                if (sInstance == null) {
+                    sInstance = new InteractionJankMonitor(new HandlerThread(DEFAULT_WORKER_NAME));
                 }
-                sRenderer = renderer == null ? view.getThreadedRenderer() : renderer;
-                sRunningTracker = map == null ? new HashMap<>() : map;
-                sWorker = worker == null ? new HandlerThread("Aot-Worker") : worker;
-                sWorker.start();
-                sInitialized = true;
             }
         }
+        return sInstance;
+    }
+
+    /**
+     * This constructor should be only public to tests.
+     * @param worker the worker thread for the callbacks
+     */
+    @VisibleForTesting
+    public InteractionJankMonitor(@NonNull HandlerThread worker) {
+        mRunningTrackers = new SparseArray<>();
+        mTimeoutActions = new SparseArray<>();
+        mWorker = worker;
+    }
+
+    /**
+     * Init InteractionJankMonitor for later instrumentation.
+     * @param view Any view in the view tree to get context and ThreadedRenderer.
+     * @return boolean true if the instance has been initialized successfully.
+     */
+    public boolean init(@NonNull View view) {
+        //TODO (163505250): This should be no-op if not in droid food rom.
+        if (!mInitialized) {
+            synchronized (this) {
+                if (!mInitialized) {
+                    if (!view.isAttachedToWindow()) {
+                        Log.d(TAG, "Expect an attached view!", new Throwable());
+                        return false;
+                    }
+                    mRenderer = new ThreadedRendererWrapper(view.getThreadedRenderer());
+                    mMetrics = new FrameMetricsWrapper();
+                    mWorker.start();
+                    mInitialized = true;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Create a {@link FrameTracker} instance.
+     * @param session the session associates with this tracker
+     * @return instance of the FrameTracker
+     */
+    @VisibleForTesting
+    public FrameTracker createFrameTracker(Session session) {
+        synchronized (this) {
+            if (!mInitialized) return null;
+            return new FrameTracker(session, mWorker.getThreadHandler(), mRenderer, mMetrics);
+        }
     }
 
     /**
-     * Must invoke init() before invoking this method.
+     * Begin a trace session, must invoke {@link #init(View)} before invoking this method.
+     * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+     * @return boolean true if the tracker is started successfully, false otherwise.
      */
-    public static void begin(@NonNull @CujType int cujType) {
-        begin(cujType, null);
+    public boolean begin(@CujType int cujType) {
+        //TODO (163505250): This should be no-op if not in droid food rom.
+        synchronized (this) {
+            return begin(cujType, 0L /* timeout */);
+        }
     }
 
     /**
-     * Should be only invoked internally or from unit tests.
+     * Begin a trace session, must invoke {@link #init(View)} before invoking this method.
+     * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+     * @param timeout the elapsed time in ms until firing the timeout action.
+     * @return boolean true if the tracker is started successfully, false otherwise.
      */
-    @VisibleForTesting
-    public static void begin(@NonNull @CujType int cujType, FrameTracker tracker) {
+    public boolean begin(@CujType int cujType, long timeout) {
         //TODO (163505250): This should be no-op if not in droid food rom.
-        //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
-        synchronized (LOCK) {
-            checkInitStateLocked();
-            Session session = new Session(cujType);
-            FrameTracker currentTracker = getTracker(session.getName());
-            if (currentTracker != null) return;
-            if (tracker == null) {
-                tracker = new FrameTracker(session, sWorker.getThreadHandler(), sRenderer);
+        synchronized (this) {
+            if (!mInitialized) {
+                Log.d(TAG, "Not initialized!", new Throwable());
+                return false;
             }
-            sRunningTracker.put(session.getName(), tracker);
+            Session session = new Session(cujType);
+            FrameTracker tracker = getTracker(session);
+            // Skip subsequent calls if we already have an ongoing tracing.
+            if (tracker != null) return false;
+
+            // begin a new trace session.
+            tracker = createFrameTracker(session);
+            mRunningTrackers.put(cujType, tracker);
             tracker.begin();
+
+            // Cancel the trace if we don't get an end() call in specified duration.
+            timeout = timeout > 0L ? timeout : DEFAULT_TIMEOUT_MS;
+            Runnable timeoutAction = () -> cancel(cujType);
+            mTimeoutActions.put(cujType, timeoutAction);
+            mWorker.getThreadHandler().postDelayed(timeoutAction, timeout);
+            return true;
         }
     }
 
     /**
-     * Must invoke init() before invoking this method.
+     * End a trace session, must invoke {@link #init(View)} before invoking this method.
+     * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+     * @return boolean true if the tracker is ended successfully, false otherwise.
      */
-    public static void end(@NonNull @CujType int cujType) {
+    public boolean end(@CujType int cujType) {
         //TODO (163505250): This should be no-op if not in droid food rom.
-        //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
-        synchronized (LOCK) {
-            checkInitStateLocked();
-            Session session = new Session(cujType);
-            FrameTracker tracker = getTracker(session.getName());
-            if (tracker != null) {
-                tracker.end();
-                sRunningTracker.remove(session.getName());
+        synchronized (this) {
+            if (!mInitialized) {
+                Log.d(TAG, "Not initialized!", new Throwable());
+                return false;
             }
-        }
-    }
+            // remove the timeout action first.
+            Runnable timeout = mTimeoutActions.get(cujType);
+            if (timeout != null) {
+                mWorker.getThreadHandler().removeCallbacks(timeout);
+                mTimeoutActions.remove(cujType);
+            }
 
-    private static void checkInitStateLocked() {
-        if (!sInitialized) {
-            throw new IllegalStateException("InteractionJankMonitor not initialized!");
+            Session session = new Session(cujType);
+            FrameTracker tracker = getTracker(session);
+            // Skip this call since we haven't started a trace yet.
+            if (tracker == null) return false;
+            tracker.end();
+            mRunningTrackers.remove(session.getCuj());
+            return true;
         }
     }
 
     /**
-     * Should be only invoked from unit tests.
+     * Cancel the trace session, must invoke {@link #init(View)} before invoking this method.
+     * @return boolean true if the tracker is cancelled successfully, false otherwise.
+     */
+    public boolean cancel(@CujType int cujType) {
+        //TODO (163505250): This should be no-op if not in droid food rom.
+        synchronized (this) {
+            if (!mInitialized) {
+                Log.d(TAG, "Not initialized!", new Throwable());
+                return false;
+            }
+            // remove the timeout action first.
+            Runnable timeout = mTimeoutActions.get(cujType);
+            if (timeout != null) {
+                mWorker.getThreadHandler().removeCallbacks(timeout);
+                mTimeoutActions.remove(cujType);
+            }
+
+            Session session = new Session(cujType);
+            FrameTracker tracker = getTracker(session);
+            // Skip this call since we haven't started a trace yet.
+            if (tracker == null) return false;
+            tracker.cancel();
+            mRunningTrackers.remove(session.getCuj());
+            return true;
+        }
+    }
+
+    private void destroy() {
+        synchronized (this) {
+            int trackers = mRunningTrackers.size();
+            for (int i = 0; i < trackers; i++) {
+                mRunningTrackers.valueAt(i).cancel();
+            }
+            mRunningTrackers = null;
+            mTimeoutActions.clear();
+            mTimeoutActions = null;
+            mWorker.quit();
+            mWorker = null;
+        }
+    }
+
+    /**
+     * Abandon current instance.
      */
     @VisibleForTesting
-    public static void reset() {
-        sInitialized = false;
-        sRenderer = null;
-        sRunningTracker = null;
-        if (sWorker != null) {
-            sWorker.quit();
-            sWorker = null;
+    public static void abandon() {
+        if (sInstance == null) return;
+        synchronized (InteractionJankMonitor.class) {
+            if (sInstance == null) return;
+            sInstance.destroy();
+            sInstance = null;
         }
     }
 
-    private static FrameTracker getTracker(String sessionName) {
-        synchronized (LOCK) {
-            return sRunningTracker.get(sessionName);
+    private FrameTracker getTracker(Session session) {
+        synchronized (this) {
+            if (!mInitialized) return null;
+            return mRunningTrackers.get(session.getCuj());
         }
     }
 
     /**
      * Trigger the perfetto daemon to collect and upload data.
      */
-    public static void trigger() {
-        sWorker.getThreadHandler().post(
-                () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+    @VisibleForTesting
+    public void trigger() {
+        synchronized (this) {
+            if (!mInitialized) return;
+            mWorker.getThreadHandler().post(
+                    () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+        }
     }
 
     /**
      * A class to represent a session.
      */
     public static class Session {
-        private @CujType int mId;
+        private @CujType int mCujType;
 
-        public Session(@CujType int session) {
-            mId = session;
+        public Session(@CujType int cujType) {
+            mCujType = cujType;
         }
 
-        public int getId() {
-            return mId;
+        public int getCuj() {
+            return mCujType;
         }
 
         public int getStatsdInteractionType() {
-            return CUJ_TO_STATSD_INTERACTION_TYPE[mId];
+            return CUJ_TO_STATSD_INTERACTION_TYPE[mCujType];
         }
 
         /** Describes whether the measurement from this session should be written to statsd. */
@@ -196,7 +318,7 @@
         }
 
         public String getName() {
-            return "CujType<" + mId + ">";
+            return "Cuj<" + getCuj() + ">";
         }
     }
 
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index c9156c1..c0f44a5 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -33,7 +33,11 @@
     public void log(UiEventEnum event, int uid, String packageName) {
         final int eventID = event.getId();
         if (eventID > 0) {
-            FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName);
+            FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED,
+                    /* event_id = 1 */ eventID,
+                    /* uid = 2 */ uid,
+                    /* package_name = 3 */ packageName,
+                    /* instance_id = 4 */ 0);
         }
     }
 
@@ -42,8 +46,11 @@
             InstanceId instance) {
         final int eventID = event.getId();
         if ((eventID > 0)  && (instance != null)) {
-            FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED, eventID, uid, packageName,
-                    instance.getId());
+            FrameworkStatsLog.write(FrameworkStatsLog.UI_EVENT_REPORTED,
+                    /* event_id = 1 */ eventID,
+                    /* uid = 2 */ uid,
+                    /* package_name = 3 */ packageName,
+                    /* instance_id = 4 */ instance.getId());
         } else {
             log(event, uid, packageName);
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7516a87..4a0e26a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -156,7 +156,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 187 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 188 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -14576,6 +14576,7 @@
         mDailyStartTimeMs = in.readLong();
         mNextMinDailyDeadlineMs = in.readLong();
         mNextMaxDailyDeadlineMs = in.readLong();
+        mBatteryTimeToFullSeconds = in.readLong();
 
         mStartCount++;
 
@@ -15068,6 +15069,7 @@
         out.writeLong(mDailyStartTimeMs);
         out.writeLong(mNextMinDailyDeadlineMs);
         out.writeLong(mNextMaxDailyDeadlineMs);
+        out.writeLong(mBatteryTimeToFullSeconds);
 
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -15651,6 +15653,7 @@
         mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mLastWriteTimeMs = in.readLong();
+        mBatteryTimeToFullSeconds = in.readLong();
 
         mRpmStats.clear();
         int NRPMS = in.readInt();
@@ -15850,6 +15853,7 @@
         mDischargeLightDozeCounter.writeToParcel(out);
         mDischargeDeepDozeCounter.writeToParcel(out);
         out.writeLong(mLastWriteTimeMs);
+        out.writeLong(mBatteryTimeToFullSeconds);
 
         out.writeInt(mRpmStats.size());
         for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1f8a829..4512fba 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1105,15 +1105,18 @@
                     : controller.getSystemBarsAppearance();
 
             if (insets != null) {
-                final Insets systemBarInsets = insets.getInsets(WindowInsets.Type.systemBars());
-                final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
-                        WindowInsets.Type.systemBars());
                 final boolean clearCompatInsets = clearCompatInsets(attrs.type, attrs.flags,
                         getResources().getConfiguration().windowConfiguration.getWindowingMode());
-                mLastTopInset = clearCompatInsets ? 0 : systemBarInsets.top;
-                mLastBottomInset = clearCompatInsets ? 0 : systemBarInsets.bottom;
-                mLastRightInset = clearCompatInsets ? 0 : systemBarInsets.right;
-                mLastLeftInset = clearCompatInsets ? 0 : systemBarInsets.left;
+                final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
+                        WindowInsets.Type.systemBars());
+                final Insets systemInsets = clearCompatInsets
+                        ? Insets.NONE
+                        : Insets.min(insets.getInsets(WindowInsets.Type.systemBars()
+                                | WindowInsets.Type.displayCutout()), stableBarInsets);
+                mLastTopInset = systemInsets.top;
+                mLastBottomInset = systemInsets.bottom;
+                mLastRightInset = systemInsets.right;
+                mLastLeftInset = systemInsets.left;
 
                 // Don't animate if the presence of stable insets has changed, because that
                 // indicates that the window was either just added and received them for the
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 9f7436a..9874c6a 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -72,7 +72,9 @@
             Consts.TAG_WM),
     WM_DEBUG_WINDOW_ORGANIZER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
             Consts.TAG_WM),
-    TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+    WM_DEBUG_SYNC_ENGINE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
 
     private final boolean mEnabled;
     private volatile boolean mLogToProto;
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 6b754ca..396a84f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1520,7 +1520,12 @@
         readPublicLibrariesListFile(new File("/vendor/etc/public.libraries.txt"));
         String[] dirs = {"/system/etc", "/system_ext/etc", "/product/etc"};
         for (String dir : dirs) {
-            for (File f : (new File(dir)).listFiles()) {
+            File[] files = new File(dir).listFiles();
+            if (files == null) {
+                Slog.w(TAG, "Public libraries file folder missing: " + dir);
+                continue;
+            }
+            for (File f : files) {
                 String name = f.getName();
                 if (name.startsWith("public.libraries-") && name.endsWith(".txt")) {
                     readPublicLibrariesListFile(f);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index ef0eeec..5a859aa 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -792,7 +792,7 @@
 }
 
 static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) {
-    jlong heapsSizeKb = 0;
+    jlong heapsSizeKb = -1;
     uint64_t size;
 
     if (meminfo::ReadIonHeapsSizeKb(&size)) {
@@ -803,7 +803,7 @@
 }
 
 static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
-    jlong poolsSizeKb = 0;
+    jlong poolsSizeKb = -1;
     uint64_t size;
 
     if (meminfo::ReadIonPoolsSizeKb(&size)) {
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 5f590be..e1a980c 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -120,6 +120,14 @@
     }
     optional Assist assist = 7;
 
+    message AssistHandles {
+        option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+        optional SettingProto learning_time_elapsed_millis = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto learning_event_count = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    }
+    optional AssistHandles assist_handles = 86;
+
     message Autofill {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -617,5 +625,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 86;
+    // Next tag = 87;
 }
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f5facea..b54dfc0 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d uur lank</item>
       <item quantity="one">1 uur lank</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (volgende wekker)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Totdat jy dit afskakel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index bea1861..668ce42 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">ለ%d ሰዓት</item>
       <item quantity="other">ለ%d ሰዓት</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ድረስ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"እስከ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ቀጣይ ማንቂያ)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"እስኪያጠፉት ድረስ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6832344..fdb351c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1953,6 +1953,7 @@
       <item quantity="other">‏لمدة %d من الساعات</item>
       <item quantity="one">لمدة ساعة</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"حتى <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (التنبيه التالي)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"إلى أن يتم إيقاف الوضع"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index bad330e..93ce15f 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">%d ঘণ্টাৰ বাবে</item>
       <item quantity="other">%d ঘণ্টাৰ বাবে</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পৰ্যন্ত"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পৰ্যন্ত"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (পৰৱৰ্তী এলার্ম) পর্যন্ত"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"আপুনি অফ নকৰা পর্যন্ত"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index c721bbf..01b815b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d saat üçün</item>
       <item quantity="one">1 saat üçün</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Bu vaxtadək: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Saat <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> qədər"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> radəsinə qədər (növbəti siqnal)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Deaktiv edənə qədər"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 93ddbe5..e2fc8f1 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -243,7 +243,7 @@
     <string name="global_action_power_off" msgid="4404936470711393203">"Isključi"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"Napajanje"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Restartuj"</string>
-    <string name="global_action_emergency" msgid="1387617624177105088">"Hitni poziv"</string>
+    <string name="global_action_emergency" msgid="1387617624177105088">"Hitan poziv"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Izveštaj o grešci"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"Završi sesiju"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"Snimak ekrana"</string>
@@ -835,7 +835,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite „Meni“ za otključavanje."</string>
     <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Unesite šablon za otključavanje"</string>
-    <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
+    <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitan poziv"</string>
     <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazad na poziv"</string>
     <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tačno!"</string>
     <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probajte ponovo"</string>
@@ -1815,7 +1815,7 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n• uključuje tamnu temu\n• isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n• uključuje tamnu temu\n• isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
     <string name="battery_saver_description" msgid="6794188153647295212">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n• uključuje tamnu temu\n• isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string>
@@ -1860,6 +1860,7 @@
       <item quantity="few">Za %d s</item>
       <item quantity="other">Za %d s</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sledeći alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dok ne isključite"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 08aeacf..45008f2 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="many">На %d гадз</item>
       <item quantity="other">На %d гадз</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Да <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (наступны будзільнік)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Пакуль не выключыце"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e49ae26..0c2c022 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">За %d ч</item>
       <item quantity="one">За 1 ч</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"До следващия будилник (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"До изключване"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 22589cd..b10d8dc 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="one">%d ঘন্টার জন্য</item>
       <item quantity="other">%d ঘন্টার জন্য</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পর্যন্ত"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> পর্যন্ত (পরবর্তী অ্যালার্ম)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 755ee47..17c0d1d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -593,7 +593,7 @@
     <string name="face_acquired_not_detected" msgid="2945945257956443257">"Postavite lice direktno ispred telefona"</string>
     <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše pokreta. Držite telefon mirno."</string>
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte lice."</string>
-    <string name="face_acquired_too_different" msgid="4699657338753282542">"Nije više moguće prepoznati lice. Pokušajte opet."</string>
+    <string name="face_acquired_too_different" msgid="4699657338753282542">"Više nije moguće prepoznati lice. Pokušajte opet."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"Previše slično, promijenite položaj."</string>
     <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Malo manje zakrenite glavu."</string>
     <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"Malo manje zakrenite glavu."</string>
@@ -1860,6 +1860,7 @@
       <item quantity="few">%d sata</item>
       <item quantity="other">%d sati</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sljedeći alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dok ne isključite"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4f55bf5..e0c709d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1224,7 +1224,7 @@
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"S\'ha establert el so de silenci"</string>
     <string name="volume_call" msgid="7625321655265747433">"Volum en trucada"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volum en trucada per Bluetooth"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"Volum de l\'alarma"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"Volum d\'alarma"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Volum de notificacions"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"Volum"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Volum del Bluetooth"</string>
@@ -1829,6 +1829,7 @@
       <item quantity="other">Durant %d h</item>
       <item quantity="one">Durant 1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Finalitza: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Fins a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (propera alarma)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Fins que no el desactivis"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fcf9b83..095ec69 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="other">%d h</item>
       <item quantity="one">1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (příští budík)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dokud tuto funkci nevypnete"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0b7e396..499b9de 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">I %d t.</item>
       <item quantity="other">I %d t.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (næste alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Indtil du deaktiverer"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index faa78df..867efac 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="other">Für %d h</item>
       <item quantity="one">Für 1 h</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"Bis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Bis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nächste Weckzeit)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Bis zur Deaktivierung"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2e1b56a..d4d1c5a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Για %d ώρες</item>
       <item quantity="one">Για 1 ώρα</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Έως <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Έως τις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Μέχρι τις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (επόμενο ξυπνητήρι)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Μέχρι την απενεργοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index dcfbf5a..f140ce3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">For %d hr</item>
       <item quantity="one">For 1 hr</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Until you turn off"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 65f2426..e814bdf 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">For %d hr</item>
       <item quantity="one">For 1 hr</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Until you turn off"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d38e2fe..73f1562 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">For %d hr</item>
       <item quantity="one">For 1 hr</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Until you turn off"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 30a9bf88..122ea7f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">For %d hr</item>
       <item quantity="one">For 1 hr</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Until <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (next alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Until you turn off"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 6503f7c..53d8c66 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎For %d hr‎‏‎‎‏‎</item>
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎For 1 hr‎‏‎‎‏‎</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‎Until ‎‏‎‎‏‏‎<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎Until ‎‏‎‎‏‏‎<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎Until ‎‏‎‎‏‏‎<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ (next alarm)‎‏‎‎‏‎"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎Until you turn off‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 2308b5a..953b6fc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Durante %d horas</item>
       <item quantity="one">Durante 1 hora</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hasta la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta la hora <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Hasta que lo desactives"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 67350cb0..465d2ec 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Durante %d horas</item>
       <item quantity="one">Durante 1 hora</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hasta <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hasta las <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Hasta que lo desactives"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 3929ed4..6d2a4c0f 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d h</item>
       <item quantity="one">1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Kuni <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (järgmine äratus)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Kuni välja lülitate"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index c93dbbf..7241b97 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d orduz</item>
       <item quantity="one">Ordubetez</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte (hurrengo alarma)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Zuk desaktibatu arte"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1ee4be5..02f4728 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1267,7 +1267,7 @@
     <string name="sms_control_title" msgid="4748684259903148341">"درحال ارسال پیامک‌ها"</string>
     <string name="sms_control_message" msgid="6574313876316388239">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; درحال ارسال تعداد زیادی پیامک است. آیا اجازه می‌دهید این برنامه همچنان پیامک ارسال کند؟"</string>
     <string name="sms_control_yes" msgid="4858845109269524622">"مجاز است"</string>
-    <string name="sms_control_no" msgid="4845717880040355570">"اجازه ندارد"</string>
+    <string name="sms_control_no" msgid="4845717880040355570">"مجاز نبودن"</string>
     <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; مایل است پیامی به &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; ارسال کند."</string>
     <string name="sms_short_code_details" msgid="2723725738333388351">"این مورد "<b>"شاید هزینه‌ای"</b>" را به حساب دستگاه همراهتان بگذارد."</string>
     <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"این مورد هزینه‌ای را به حساب دستگاه همراهتان می‌گذارد."</b></string>
@@ -1413,7 +1413,7 @@
     <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"می‌خواهید به این درخواست اجازه دهید؟"</string>
     <string name="grant_permissions_header_text" msgid="3420736827804657201">"درخواست دسترسی"</string>
     <string name="allow" msgid="6195617008611933762">"ارزیابی‌شده"</string>
-    <string name="deny" msgid="6632259981847676572">"اجازه ندارد"</string>
+    <string name="deny" msgid="6632259981847676572">"مجاز نبودن"</string>
     <string name="permission_request_notification_title" msgid="1810025922441048273">"مجوز درخواست شد"</string>
     <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"مجوز\nبرای حساب <xliff:g id="ACCOUNT">%s</xliff:g> درخواست شد."</string>
     <string name="forward_intent_to_owner" msgid="4620359037192871015">"شما از این برنامه در خارج از نمایه کاری‌تان استفاده می‌کنید"</string>
@@ -1639,7 +1639,7 @@
     <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"مشاهده و انجام کنش‌ها"</string>
     <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"این عملکرد می‌تواند با برنامه یا حسگری سخت‌افزاری تعاملاتتان را ردیابی کند و ازطرف شما با برنامه‌ها تعامل داشته باشد."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"مجاز"</string>
-    <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"رد کردن"</string>
+    <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"مجاز نبودن"</string>
     <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"برای استفاده از ویژگی، روی آن ضربه بزنید:"</string>
     <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"انتخاب ویژگی‌های موردنظر برای استفاده با دکمه دسترس‌پذیری"</string>
     <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"انتخاب ویژگی‌های موردنظر برای استفاده با میان‌بر کلید میزان صدا"</string>
@@ -1829,6 +1829,7 @@
       <item quantity="one">‏برای %d ساعت</item>
       <item quantity="other">‏برای %d ساعت</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"تا <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (زنگ بعدی)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"تا زمانی‌که آن را خاموش کنید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1eff983..0c94f35 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d tunnin ajan</item>
       <item quantity="one">1 tunnin ajan</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> asti"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Kunnes kello on <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> asti (seuraava hälytys)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Kunnes laitat pois päältä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index c6f347b..dcfe8ad 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Pendant %d h</item>
       <item quantity="other">Pendant %d h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Jusqu\'à la désactivation"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6307c35..5fc2d69 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Pendant %d h</item>
       <item quantity="other">Pendant %d h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Jusqu\'à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarme suivante)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Jusqu\'à la désactivation"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 0f28146..a6eac55 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Durante %d h</item>
       <item quantity="one">Durante unha h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Ata: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Ata as <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Ata as <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próxima alarma)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Ata a desactivación"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f11a228..6b4bbf3 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="one">%d કલાક માટે</item>
       <item quantity="other">%d કલાક માટે</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> સુધી"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (આગલા એલાર્મ) સુધી"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"તમે બંધ ન કરો ત્યાં સુધી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 7b0bd23..3bf9dcd 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">%d घंटे के लिए</item>
       <item quantity="other">%d घंटे के लिए</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> तक"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> तक"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (अगले अलार्म) तक"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"जब तक आप बंद नहीं करते"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index eb41c9f..d350d04 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1860,6 +1860,7 @@
       <item quantity="few">%d h</item>
       <item quantity="other">%d h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sljedeći alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dok ne isključite"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3b44295..70f87b6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d órán keresztül</item>
       <item quantity="one">1 órán keresztül</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Eddig: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ez a következő ébresztés)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Kikapcsolásig"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 4f66b6e..32ac6a8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -48,7 +48,7 @@
     <string name="invalidPin" msgid="7542498253319440408">"Մուտքագրեք PIN, որը 4-ից 8 թիվ է:"</string>
     <string name="invalidPuk" msgid="8831151490931907083">"Մուտքագրեք PUK, որն 8 կամ ավել թիվ ունի:"</string>
     <string name="needPuk" msgid="7321876090152422918">"Ձեր SIM քարտը PUK-ով կողպված է: Մուտքագրեք PUK կոդը այն ապակողպելու համար:"</string>
-    <string name="needPuk2" msgid="7032612093451537186">"Մուտքագրեք PUK2-ը` SIM քարտն արգելահանելու համար:"</string>
+    <string name="needPuk2" msgid="7032612093451537186">"Մուտքագրեք PUK2-ը՝ SIM քարտն արգելահանելու համար:"</string>
     <string name="enablePin" msgid="2543771964137091212">"Ձախողվեց: Միացրեք SIM/RUIM կողպումը:"</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
       <item quantity="one">Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն արգելափակվելու է:</item>
@@ -411,7 +411,7 @@
     <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Թույլ է տալիս հավելվածին փոփոխել ձեր պլանշետի զանգերի մատյանը, այդ թվում` մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել` ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Թույլ է տալիս հավելվածին փոփոխել Android TV սարքի զանգերի մատյանը, այդ թվում՝ մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել՝ ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string>
     <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Թույլ է տալիս հավելվածին փոփոխել ձեր հեռախոսի զանգերի մատյանը, այդ թվում` մուտքային և ելքային զանգերի մասին տվյալները: Վնասարար հավելվածները կարող են սա օգտագործել` ձեր զանգերի մատյանը ջնջելու կամ փոփոխելու համար:"</string>
-    <string name="permlab_bodySensors" msgid="3411035315357380862">"օգտագործել մարմնի սենսորները (օրինակ` սրտի կծկումների հաճախականության չափիչ)"</string>
+    <string name="permlab_bodySensors" msgid="3411035315357380862">"օգտագործել մարմնի սենսորները (օրինակ՝ սրտի կծկումների հաճախականության չափիչ)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Հավելվածին թույլ է տալիս մուտք ունենալ սենսորների տվյալներին, որոնք վերահսկում են ձեր ֆիզիկական վիճակը, օրինակ՝ ձեր սրտի զարկերը:"</string>
     <string name="permlab_readCalendar" msgid="6408654259475396200">"Կարդալ օրացույցի միջոցառումները և տվյալները"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Այս հավելվածը կարող է կարդալ օրացույցի՝ ձեր պլանշետում պահված բոլոր միջոցառումները, ինչպես նաև հրապարակել կամ պահել ձեր օրացույցի տվյալները:"</string>
@@ -430,7 +430,7 @@
     <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"տեղադրության մասին տվյալների հասանելիություն ֆոնային ռեժիմում"</string>
     <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Այս հավելվածը ցանկացած ժամանակ կարող է տեսնել տեղադրության տվյալները, նույնիսկ երբ այն ակտիվ չէ։"</string>
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"փոխել ձեր աուդիո կարգավորումները"</string>
-    <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ` ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string>
+    <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ՝ ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string>
     <string name="permlab_recordAudio" msgid="1208457423054219147">"ձայնագրել աուդիո ֆայլ"</string>
     <string name="permdesc_recordAudio" msgid="3976213377904701093">"Այս հավելվածը ցանկացած պահի կարող է ձայնագրել խոսափողի օգնությամբ:"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ուղարկել հրամաններ SIM քարտին"</string>
@@ -495,7 +495,7 @@
     <string name="permlab_changeTetherState" msgid="9079611809931863861">"փոխել միացված կապը"</string>
     <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Թույլ է տալիս հավելվածին փոխել կապված ցանցի միացման կարգավիճակը:"</string>
     <string name="permlab_accessWifiState" msgid="5552488500317911052">"դիտել Wi-Fi կապերը"</string>
-    <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Թույլ է տալիս հավելվածին տեսնել Wi-Fi ցանցի տեղեկություններ, ինչպես օրինակ` արդյոք Wi-Fi-ը միացված է, թե` ոչ, և միացված Wi-Fi սարքի անունը:"</string>
+    <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Թույլ է տալիս հավելվածին տեսնել Wi-Fi ցանցի տեղեկություններ, ինչպես օրինակ՝ արդյոք Wi-Fi-ը միացված է, թե` ոչ, և միացված Wi-Fi սարքի անունը:"</string>
     <string name="permlab_changeWifiState" msgid="7947824109713181554">"միանալ Wi-Fi-ին և անջատվել դրանից"</string>
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Թույլ է տալիս հավելվածին միանալ Wi-Fi մուտքի կետերին և անջատվել այդ կետերից, ինչպես նաև կատարել սարքի կարգավորման փոփոխություններ Wi-Fi ցանցերի համար:"</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"թույլատրել Բազմասփյուռ Wi-Fi-ի ընդունումը"</string>
@@ -615,7 +615,7 @@
   </string-array>
     <string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string>
     <string name="permlab_readSyncSettings" msgid="6250532864893156277">"կարդալ համաժամացման կարգավորումները"</string>
-    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
+    <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ՝ այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
     <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"համաժամացումը փոխարկել միացվածի և անջատվածի"</string>
     <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Թույլ է տալիս հավելվածին փոփոխել համաժամացման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամացումը հաշվի հետ:"</string>
     <string name="permlab_readSyncStats" msgid="3747407238320105332">"կարդալ համաժամացման վիճակագրությունը"</string>
@@ -876,7 +876,7 @@
     <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Մոռացե՞լ եք սխեման:"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Հաշվի ապակողպում"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Չափից շատ սխեմայի փորձեր"</string>
-    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string>
+    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Ապակողպելու համար՝ մուտք գործեք ձեր Google հաշվով:"</string>
     <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Օգտանուն (էլփոստ)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Գաղտնաբառ"</string>
     <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Մուտք գործել"</string>
@@ -1407,7 +1407,7 @@
     <string name="ime_action_done" msgid="6299921014822891569">"Պատրաստ է"</string>
     <string name="ime_action_previous" msgid="6548799326860401611">"Նախորդ"</string>
     <string name="ime_action_default" msgid="8265027027659800121">"Կատարել"</string>
-    <string name="dial_number_using" msgid="6060769078933953531">"Հավաքել հեռախոսահամարը`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string>
+    <string name="dial_number_using" msgid="6060769078933953531">"Հավաքել հեռախոսահամարը՝\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string>
     <string name="create_contact_using" msgid="6200708808003692594">"Ստեղծել կոնտակտ`\nօգտագործելով <xliff:g id="NUMBER">%s</xliff:g>-ը"</string>
     <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Հետևյալ մեկ կամ մի քանի հավելվածներին թույլտվություն է անհրաժեշտ՝ այժմ և հետագայում ձեր հաշվի տվյալներն օգտագործելու համար։"</string>
     <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Թույլատրե՞լ"</string>
@@ -1474,7 +1474,7 @@
     <string name="number_picker_increment_button" msgid="7621013714795186298">"Ավելացնել"</string>
     <string name="number_picker_decrement_button" msgid="5116948444762708204">"Նվազեցնել"</string>
     <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> հպեք և պահեք:"</string>
-    <string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Սահեցրեք վերև` ավելացնելու համար, և ներքև` նվազեցնելու համար:"</string>
+    <string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Սահեցրեք վերև՝ ավելացնելու համար, և ներքև՝ նվազեցնելու համար:"</string>
     <string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Աճեցնել րոպեն"</string>
     <string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Նվազեցնել րոպեն"</string>
     <string name="time_picker_increment_hour_button" msgid="3063572723197178242">"Աճեցնել ժամը"</string>
@@ -1598,7 +1598,7 @@
     <string name="kg_invalid_puk" msgid="4809502818518963344">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN ծածկագրերը չեն համընկնում"</string>
     <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Չափից շատ սխեմայի փորձեր"</string>
-    <string name="kg_login_instructions" msgid="3619844310339066827">"Ապակողպելու համար` մուտք գործեք ձեր Google հաշվով:"</string>
+    <string name="kg_login_instructions" msgid="3619844310339066827">"Ապակողպելու համար՝ մուտք գործեք ձեր Google հաշվով:"</string>
     <string name="kg_login_username_hint" msgid="1765453775467133251">"Օգտանուն (էլփոստ)"</string>
     <string name="kg_login_password_hint" msgid="3330530727273164402">"Գաղտնաբառը"</string>
     <string name="kg_login_submit_button" msgid="893611277617096870">"Մուտք գործել"</string>
@@ -1829,6 +1829,7 @@
       <item quantity="one">%d ժամով</item>
       <item quantity="other">%d ժամով</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Մինչև <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Մինչև <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Մինչև ժ. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ը (հաջորդ զարթուցիչը)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Մինչև չանջատեք"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f6f5040..f8ba016 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Selama %d jam</item>
       <item quantity="one">Selama 1 jam</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Sampai <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarm berikutnya)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Sampai Anda menonaktifkannya"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 899fa52..9278bbb 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Í %d klst.</item>
       <item quantity="other">Í %d klst.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Þangað til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (næsta viðvörun)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Þar til þú slekkur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 14bfa03..b962d8b 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Per %d ore</item>
       <item quantity="one">Per 1 ora</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Fino a: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Fino alla disattivazione"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 2b6d226..821e4fd 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="other">‏למשך %d שעות</item>
       <item quantity="one">למשך שעה אחת</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"עד <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ההתראה הבאה)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"עד הכיבוי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index fdb505b..4b48495 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d時間</item>
       <item quantity="one">1時間</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>まで"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(次のアラーム)まで"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"自分が OFF にするまで"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3d0d88b..cdac647 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d სთ.</item>
       <item quantity="one">1 სთ.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-მდე (შემდეგი მაღვიძარა)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"გამორთვამდე"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 9798cc9..608ed1e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d сағат</item>
       <item quantity="one">1 сағат</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> дейін (келесі дабыл)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Өшірілгенге дейін"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index a0b8faa..14b0189 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">អស់រយៈពេល %d ម៉ោង</item>
       <item quantity="one">អស់រយៈពេល 1 ម៉ោង</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"រហូត​ដល់​ម៉ោង <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"រហូត​ដល់ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"រហូតដល់ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ម៉ោងរោទិ៍បន្ទាប់)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"រហូតទាល់តែ​អ្នកបិទ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c7786ae..0fe1c24 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="one">%d ಗಂಟೆಗೆ</item>
       <item quantity="other">%d ಗಂಟೆಗೆ</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ವರೆಗೆ (ಮುಂದಿನ ಅಲಾರಮ್)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 78c3286..e3406c1b 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d시간 동안</item>
       <item quantity="one">1시간 동안</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>까지"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>까지"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(다음 알람)까지"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"사용 중지할 때까지"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 162b4d3..3268d16 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d саатка</item>
       <item quantity="one">1 саатка</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> чейин (кийинки ойготкуч)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Бул функция өчүрүлгөнгө чейин"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 4451139..d22ce0c 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">ເປັນ​ເວ​ລາ %d ຊມ</item>
       <item quantity="one">ເປັນ​ເວ​ລາ 1 ຊມ</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"ຈົນຮອດ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"ຈົນ​ຮອດ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"ຈົນ​ກ​່​ວາ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ສັນ​ຍານ​ເຕືອນ​ຕໍ່ໄປ​)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ຈົນກວ່າທ່ານຈະປິດ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fa07978..ff687c5 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="many">%d val.</item>
       <item quantity="other">%d val.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Iki <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (kitas signalas)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Kol išjungsite"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index e8107fb..2cb6058 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1860,6 +1860,7 @@
       <item quantity="one">%d h</item>
       <item quantity="other">%d h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Līdz: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Līdz <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Līdz plkst. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nākamais signāls)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Līdz brīdim, kad izslēgsiet"</string>
diff --git a/core/res/res/values-mcc310-mnc150-as/strings.xml b/core/res/res/values-mcc310-mnc150-as/strings.xml
deleted file mode 100644
index 2a4e46bd6..0000000
--- a/core/res/res/values-mcc310-mnc150-as/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/* //device/apps/common/assets/res/any/strings.xml
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mmcc_illegal_me" msgid="8004509200390992737">"ফ\'নৰ অনুমতি নাই MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index df7781e..bf7220c 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">За %d ч.</item>
       <item quantity="other">За %d ч.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (следниот аларм)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Додека не го исклучите"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 12c0cb4..513ed1d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d മണിക്കൂറത്തേക്ക്</item>
       <item quantity="one">ഒരു മണിക്കൂറത്തേക്ക്</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> വരെ (അടുത്ത അലാറം)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 2c041dc..b95b689 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d цагийн турш</item>
       <item quantity="one">1 цагийн турш:</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> хүртэл (дараагийн сэрүүлэг)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Таныг унтраах хүртэл"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index da6f2b7..40c7dbd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="other">%d तासासाठी</item>
       <item quantity="one">1 तासासाठी</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> पर्यंत (पुढील अलार्म)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"तुम्ही बंद करेपर्यंत"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2e78b45..fb24a06 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Selama %d jam</item>
       <item quantity="one">Selama 1 jam</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Sehingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Sehingga <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (penggera akan datang)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Sehingga anda matikan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1ebafa4..2c3fbcb 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d နာရီ အတွက်</item>
       <item quantity="one">၁ နာရီအတွက်</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> အထိ"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>အထိ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> အထိ (လာမည့် နှိုးစက်)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"သင်ပိတ်လိုက်သည် အထိ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ac21aec..fced207 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">I %d timer</item>
       <item quantity="one">I én time</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Til <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (neste alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Til du slår av"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index ee0362e..fadabe8 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="other">%d घन्टाका लागि</item>
       <item quantity="one">१ घन्टाको लागि</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> सम्म"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (अर्को अलार्म) सम्म"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"तपाईंले निष्क्रिय नपार्नुभएसम्म"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 14cfee0..337bf17 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Gedurende %d u</item>
       <item quantity="one">Gedurende 1 u</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Tot <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (volgende wekker)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Totdat je uitschakelt"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 1cb01ea..85ca065 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d ଘଣ୍ଟା ପାଇଁ</item>
       <item quantity="one">1 ଘଣ୍ଟା ପାଇଁ</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ପରବର୍ତ୍ତୀ ଆଲାର୍ମ) ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index b5560f1..ed663a8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="one">%d ਘੰਟਿਆਂ ਲਈ</item>
       <item quantity="other">%d ਘੰਟਿਆਂ ਲਈ</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ਤੱਕ"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ਤੱਕ (ਅਗਲਾ ਅਲਾਰਮ)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ ਹੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index aeebf88..16b3faf 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="other">%d godz.</item>
       <item quantity="one">1 godz.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (następny alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dopóki nie wyłączysz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index aedc047..2883d6f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Por %d horas</item>
       <item quantity="other">Por %d horas</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Até você desativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 883e4bf..3bc9530 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Durante %d h</item>
       <item quantity="one">Durante 1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Até desativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index aedc047..2883d6f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Por %d horas</item>
       <item quantity="other">Por %d horas</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Até você desativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ebc5827..d5a9297 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1860,6 +1860,7 @@
       <item quantity="other">Pentru %d h</item>
       <item quantity="one">Pentru 1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Până <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (următoarea alarmă)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Până când dezactivați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f3d13ce..3339fb5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="many">На %d часов</item>
       <item quantity="other">На %d часа</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (будильник)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Пока вы не отключите"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index cc6783a..c26f23f 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">පැය %d ක් සඳහා</item>
       <item quantity="other">පැය %d ක් සඳහා</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> දක්වා"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> තෙක්"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> තෙක් (ඊළඟ එලාමය)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index b612565..1a4f07e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="other">Na %d h</item>
       <item quantity="one">Na 1 h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (ďalší budík)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dokým funkciu nevypnete"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 3ef51a7..0079e38 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="few">%d h</item>
       <item quantity="other">%d h</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (naslednji alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Dokler ne izklopite"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 37a995a5..b29582c 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Për %d orë</item>
       <item quantity="one">Për 1 orë</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Deri në <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Deri në <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Deri në <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (alarmi tjetër)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Derisa ta çaktivizosh"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a3eb3e4..f24e285 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -243,7 +243,7 @@
     <string name="global_action_power_off" msgid="4404936470711393203">"Искључи"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"Напајање"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Рестартуј"</string>
-    <string name="global_action_emergency" msgid="1387617624177105088">"Хитни позив"</string>
+    <string name="global_action_emergency" msgid="1387617624177105088">"Хитан позив"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Извештај о грешци"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"Заврши сесију"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"Снимак екрана"</string>
@@ -835,7 +835,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притисните „Мени“ за откључавање."</string>
     <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Унесите шаблон за откључавање"</string>
-    <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Хитни позив"</string>
+    <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Хитан позив"</string>
     <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад на позив"</string>
     <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Тачно!"</string>
     <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Пробајте поново"</string>
@@ -1815,7 +1815,7 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Да би се продужило трајање батерије, Уштеда батерије:\n\n• укључује тамну тему\n• искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Да би се продужило трајање батерије, Уштеда батерије:\n\n• укључује тамну тему\n• искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
     <string name="battery_saver_description" msgid="6794188153647295212">"Да би се продужило трајање батерије, Уштеда батерије:\n\n• укључује тамну тему\n• искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string>
@@ -1860,6 +1860,7 @@
       <item quantity="few">За %d с</item>
       <item quantity="other">За %d с</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (следећи аларм)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Док не искључите"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3711e2b..5c9ce2c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">I %d tim</item>
       <item quantity="one">I en 1 tim</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Till <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (nästa alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Tills du stänger av"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 23b6c3b..55db3eb 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Kwa saa %d </item>
       <item quantity="one">Kwa saa 1 </item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Mpaka <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (kengele inayofuata)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Hadi utakapoizima"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 42b2d9c..be030d1 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d மணிநேரத்திற்கு</item>
       <item quantity="one">1 மணிநேரத்திற்கு</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> வரை"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> வரை"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> மணி (அடுத்த அலாரம்) வரை"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"ஆஃப் செய்யும் வரை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6b9caf1..0966d23 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d గం పాటు</item>
       <item quantity="one">1 గం పాటు</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> వరకు"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> వరకు"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (తర్వాత అలారం) వరకు"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"మీరు ఆఫ్‌ చేసే వరకు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4b39c63..7ff76ec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">เป็นเวลา %d ชม.</item>
       <item quantity="one">เป็นเวลา 1 ชม.</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"จนถึง <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"จนถึงเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"จนถึงเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (การปลุกครั้งถัดไป)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"จนกว่าคุณจะปิด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index beebbd2..7d9c717 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Sa loob ng %d oras</item>
       <item quantity="other">Sa loob ng %d na oras</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Hanggang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (susunod na alarm)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Hanggang sa i-off mo"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 17852a6..a658bf1 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d saat</item>
       <item quantity="one">1 saat</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Şu saate kadar: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Şu saate kadar: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sonraki alarma) saatine kadar"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Siz kapatana kadar"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 31684e0..7e81784 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1891,6 +1891,7 @@
       <item quantity="many">Протягом %d год</item>
       <item quantity="other">Протягом %d год</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"До: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"До <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (наступний будильник)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Доки ви не вимкнете"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index ed32b24..b9b9c58 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1829,6 +1829,8 @@
       <item quantity="other">‏‎%d گھنٹے کیلئے</item>
       <item quantity="one">1 گھنٹہ کیلئے</item>
     </plurals>
+    <!-- no translation found for zen_mode_until_next_day (1403042784161725038) -->
+    <skip />
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> تک"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> تک (اگلا الارم)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"یہاں تک کہ آپ آف کر دیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 7671809..5edd9dc 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d soat</item>
       <item quantity="one">1 soat</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> gacha (keyingi signal)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Rejimdan chiqilgunicha"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1899f8f..e3c7658 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">Trong %d giờ</item>
       <item quantity="one">Trong 1 giờ</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Cho tới <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Cho đến <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Cho tới <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (cảnh báo tiếp theo)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Cho đến khi bạn tắt"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0a241da..dee9d95 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d 小时</item>
       <item quantity="one">1 小时</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"结束时间:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"直到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>(闹钟下次响铃时)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"直到您将其关闭"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 6e584d6..44ad863 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d 小時</item>
       <item quantity="one">1 小時</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"直至<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"完成時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"直至<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (下一次響鬧)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"直至您關閉為止"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ab1a423..8831bf0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="other">%d 小時</item>
       <item quantity="one">1 小時</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"結束時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"結束時間:<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"到<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 為止 (下一個鬧鐘)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"直到你關閉為止"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 582d435..5fb9fa6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1829,6 +1829,7 @@
       <item quantity="one">Ngamahora angu-%d</item>
       <item quantity="other">Ngamahora angu-%d</item>
     </plurals>
+    <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Kuze kube ngu-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (i-alamu elandelayo)"</string>
     <string name="zen_mode_forever" msgid="740585666364912448">"Uze uvale isikrini"</string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 03975da..25a9bbd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4374,7 +4374,7 @@
     </string>
 
     <!-- Dialog title for dialog shown when the multiple accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
-    <string name="accessibility_shortcut_multiple_service_warning_title">Turn on accessibility features?</string>
+    <string name="accessibility_shortcut_multiple_service_warning_title">Turn on shortcut for accessibility features?</string>
 
     <!-- Message shown in dialog when user is in the process of enabling the multiple accessibility service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
     <string name="accessibility_shortcut_multiple_service_warning">Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="service" example="TalkBack">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility.</string>
@@ -4383,7 +4383,7 @@
     <string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
 
     <!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
-    <string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
+    <string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g> shortcut?</string>
 
     <!-- Message shown in dialog when user is in the process of enabling this accessibility service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
     <string name="accessibility_shortcut_single_service_warning">Holding down both volume keys for a few seconds turns on <xliff:g id="service" example="TalkBack">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility.</string>
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 2bf9848..7766b57 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -192,7 +192,7 @@
         PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putInt("k", 4);
         FixedRotationAdjustments fixedRotationAdjustments = new FixedRotationAdjustments(
-                Surface.ROTATION_90, DisplayCutout.NO_CUTOUT);
+                Surface.ROTATION_90, 1920, 1080, DisplayCutout.NO_CUTOUT);
 
         LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
                 config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
@@ -352,7 +352,8 @@
         ClientTransaction transaction = ClientTransaction.obtain(new StubAppThread(),
                 null /* activityToken */);
         transaction.addCallback(FixedRotationAdjustmentsItem.obtain(new Binder(),
-                new FixedRotationAdjustments(Surface.ROTATION_270, DisplayCutout.NO_CUTOUT)));
+                new FixedRotationAdjustments(Surface.ROTATION_270, 1920, 1080,
+                        DisplayCutout.NO_CUTOUT)));
 
         writeAndPrepareForReading(transaction);
 
diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
index 2fc42e9..3cf1722 100644
--- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
+++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java
@@ -77,8 +77,10 @@
         final int realRotation = Surface.ROTATION_0;
         final int fixedRotation = Surface.ROTATION_90;
 
-        mDisplayAdjustments.setFixedRotationAdjustments(
-                new FixedRotationAdjustments(fixedRotation, null /* cutout */));
+        final int appWidth = 1080;
+        final int appHeight = 1920;
+        mDisplayAdjustments.setFixedRotationAdjustments(new FixedRotationAdjustments(
+                fixedRotation, appWidth, appHeight, null /* cutout */));
 
         final int w = 1000;
         final int h = 2000;
@@ -95,13 +97,21 @@
         metrics.heightPixels = metrics.noncompatHeightPixels = h;
 
         final DisplayMetrics flippedMetrics = new DisplayMetrics();
-        flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h;
+        // The physical dpi should not be adjusted.
+        flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = w;
         flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h;
-        flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w;
+        flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = h;
         flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w;
 
         mDisplayAdjustments.adjustMetrics(metrics, realRotation);
 
         assertEquals(flippedMetrics, metrics);
+
+        mDisplayAdjustments.adjustGlobalAppMetrics(metrics);
+
+        assertEquals(appWidth, metrics.widthPixels);
+        assertEquals(appWidth, metrics.noncompatWidthPixels);
+        assertEquals(appHeight, metrics.heightPixels);
+        assertEquals(appHeight, metrics.noncompatHeightPixels);
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index ece5037..e17800f 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.jank;
 
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -75,20 +75,13 @@
         doNothing().when(mRenderer).addObserver(any());
         doNothing().when(mRenderer).removeObserver(any());
 
-        Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
-        mTracker = Mockito.spy(new FrameTracker(session, handler, mRenderer, mWrapper));
+        Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+        mTracker = Mockito.spy(
+                new FrameTracker(session, handler, mRenderer, mWrapper));
         doNothing().when(mTracker).triggerPerfetto();
     }
 
     @Test
-    public void testIgnoresSecondBegin() {
-        // Observer should be only added once in continuous calls.
-        mTracker.begin();
-        mTracker.begin();
-        verify(mRenderer, only()).addObserver(any());
-    }
-
-    @Test
     public void testOnlyFirstFrameOverThreshold() {
         // Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
         when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
@@ -170,6 +163,29 @@
         verify(mTracker).triggerPerfetto();
     }
 
+    @Test
+    public void testBeginCancel() {
+        mTracker.begin();
+        verify(mRenderer).addObserver(any());
+
+        // First frame - not janky
+        setupFirstFrameMockWithDuration(4);
+        mTracker.onFrameMetricsAvailable(0);
+
+        // normal frame - not janky
+        setupOtherFrameMockWithDuration(12);
+        mTracker.onFrameMetricsAvailable(0);
+
+        // a janky frame
+        setupOtherFrameMockWithDuration(30);
+        mTracker.onFrameMetricsAvailable(0);
+
+        mTracker.cancel();
+        verify(mRenderer).removeObserver(any());
+        // Since the tracker has been cancelled, shouldn't trigger perfetto.
+        verify(mTracker, never()).triggerPerfetto();
+    }
+
     private void setupFirstFrameMockWithDuration(long durationMillis) {
         doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
         doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 5c0b0c9..b669cc6 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -16,15 +16,20 @@
 
 package com.android.internal.jank;
 
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
 
 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.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Message;
 import android.view.View;
 import android.view.ViewAttachTestActivity;
 
@@ -38,17 +43,13 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.Mockito;
-import org.testng.Assert;
-
-import java.util.HashMap;
-import java.util.Map;
+import org.mockito.ArgumentCaptor;
 
 @SmallTest
 public class InteractionJankMonitorTest {
     private ViewAttachTestActivity mActivity;
     private View mView;
-    private FrameTracker mTracker;
+    private HandlerThread mWorker;
 
     @Rule
     public ActivityTestRule<ViewAttachTestActivity> mRule =
@@ -61,55 +62,52 @@
         mView = mActivity.getWindow().getDecorView();
         assertThat(mView.isAttachedToWindow()).isTrue();
 
-        InteractionJankMonitor.reset();
+        InteractionJankMonitor.abandon();
 
-        // Prepare a FrameTracker to inject.
-        Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
-        FrameMetricsWrapper wrapper = Mockito.spy(new FrameTracker.FrameMetricsWrapper());
-        ThreadedRendererWrapper renderer =
-                Mockito.spy(new ThreadedRendererWrapper(mView.getThreadedRenderer()));
-        Handler handler = mActivity.getMainThreadHandler();
-        mTracker = Mockito.spy(new FrameTracker(session, handler, renderer, wrapper));
+        Handler handler = spy(new Handler(mActivity.getMainLooper()));
+        doReturn(true).when(handler).sendMessageAtTime(any(), anyLong());
+        mWorker = spy(new HandlerThread("Interaction-jank-monitor-test"));
+        doNothing().when(mWorker).start();
+        doReturn(handler).when(mWorker).getThreadHandler();
     }
 
     @Test
     public void testBeginEnd() {
-        // Should throw exception if the view is not attached.
-        Assert.assertThrows(IllegalStateException.class,
-                () -> InteractionJankMonitor.init(new View(mActivity)));
+        // Should return false if the view is not attached.
+        InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
+        assertThat(monitor.init(new View(mActivity))).isFalse();
 
         // Verify we init InteractionJankMonitor correctly.
-        Map<String, FrameTracker> map = new HashMap<>();
-        HandlerThread worker = Mockito.spy(new HandlerThread("Aot-test"));
-        doNothing().when(worker).start();
-        InteractionJankMonitor.init(mView, mView.getThreadedRenderer(), map, worker);
-        verify(worker).start();
+        assertThat(monitor.init(mView)).isTrue();
+        verify(mWorker).start();
+
+        Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+        FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
+                new ThreadedRendererWrapper(mView.getThreadedRenderer()),
+                new FrameMetricsWrapper()));
+        doReturn(tracker).when(monitor).createFrameTracker(any());
 
         // Simulate a trace session and see if begin / end are invoked.
-        Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
-        assertThat(map.get(session.getName())).isNull();
-        InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE, mTracker);
-        verify(mTracker).begin();
-        assertThat(map.get(session.getName())).isEqualTo(mTracker);
-        InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
-        verify(mTracker).end();
-        assertThat(map.get(session.getName())).isNull();
+        assertThat(monitor.begin(session.getCuj())).isTrue();
+        verify(tracker).begin();
+        assertThat(monitor.end(session.getCuj())).isTrue();
+        verify(tracker).end();
     }
 
     @Test
     public void testCheckInitState() {
-        // Should throw exception if invoking begin / end without init invocation.
-        Assert.assertThrows(IllegalStateException.class,
-                () -> InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE));
-        Assert.assertThrows(IllegalStateException.class,
-                () -> InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE));
+        InteractionJankMonitor monitor = new InteractionJankMonitor(mWorker);
+
+        // Should return false if invoking begin / end without init invocation.
+        assertThat(monitor.begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
+        assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
 
         // Everything should be fine if invoking init first.
         boolean thrown = false;
         try {
-            InteractionJankMonitor.init(mActivity.getWindow().getDecorView());
-            InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE);
-            InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
+            monitor.init(mView);
+            assertThat(monitor.begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
+            assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
         } catch (Exception ex) {
             thrown = true;
         } finally {
@@ -117,4 +115,27 @@
         }
     }
 
+    @Test
+    public void testBeginCancel() {
+        InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
+
+        ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+        assertThat(monitor.init(mView)).isTrue();
+
+        Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+        FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
+                new ThreadedRendererWrapper(mView.getThreadedRenderer()),
+                new FrameMetricsWrapper()));
+        doReturn(tracker).when(monitor).createFrameTracker(any());
+
+        assertThat(monitor.begin(session.getCuj())).isTrue();
+        verify(tracker).begin();
+        verify(mWorker.getThreadHandler()).sendMessageAtTime(captor.capture(), anyLong());
+        Runnable runnable = captor.getValue().getCallback();
+        assertThat(runnable).isNotNull();
+        mWorker.getThreadHandler().removeCallbacks(runnable);
+        runnable.run();
+        verify(tracker).cancel();
+    }
+
 }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index dd8f40d..10c2b09 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -229,8 +229,7 @@
     <library name="android.test.base"
             file="/system/framework/android.test.base.jar" />
     <library name="android.test.mock"
-            file="/system/framework/android.test.mock.jar"
-            dependency="android.test.base" />
+            file="/system/framework/android.test.mock.jar" />
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar"
             dependency="android.test.base:android.test.mock" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6b80bb6..86e7adf 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -151,6 +151,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1910833551": {
+      "message": "SyncSet{%x:%d} Start for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "-1895337367": {
       "message": "Delete root task display=%d winMode=%d",
       "level": "VERBOSE",
@@ -463,6 +469,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1387080937": {
+      "message": "SyncSet{%x:%d} Child ready, now ready=%b and waiting on %d transactions",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "-1364754753": {
       "message": "Task vanished taskId=%d",
       "level": "VERBOSE",
@@ -481,6 +493,12 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1340783230": {
+      "message": "SyncSet{%x:%d} Added %s. now waiting on %d transactions",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "-1340540100": {
       "message": "Creating SnapshotStartingData",
       "level": "VERBOSE",
@@ -859,6 +877,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DragState.java"
     },
+    "-678300709": {
+      "message": "SyncSet{%x:%d} Trying to add %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "-668956537": {
       "message": "  THUMBNAIL %s: CREATE",
       "level": "INFO",
@@ -1735,6 +1759,12 @@
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
     },
+    "590184240": {
+      "message": "- NOT adding to sync: visible=%b hasListener=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "594260577": {
       "message": "createWallpaperAnimations()",
       "level": "DEBUG",
@@ -2005,6 +2035,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "1000601037": {
+      "message": "SyncSet{%x:%d} Set ready",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "1001904964": {
       "message": "***** BOOT TIMEOUT: forcing display enabled",
       "level": "WARN",
@@ -2599,6 +2635,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "2001924866": {
+      "message": "SyncSet{%x:%d} Finished. Reporting %d containers to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
     "2016061474": {
       "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
       "level": "VERBOSE",
@@ -2775,6 +2817,9 @@
     "WM_DEBUG_SWITCH": {
       "tag": "WindowManager"
     },
+    "WM_DEBUG_SYNC_ENGINE": {
+      "tag": "WindowManager"
+    },
     "WM_DEBUG_WINDOW_MOVEMENT": {
       "tag": "WindowManager"
     },
diff --git a/graphics/java/android/graphics/BlurShader.java b/graphics/java/android/graphics/BlurShader.java
index 779a890..3bc8119 100644
--- a/graphics/java/android/graphics/BlurShader.java
+++ b/graphics/java/android/graphics/BlurShader.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 
 /**
@@ -28,6 +29,7 @@
     private final float mRadiusX;
     private final float mRadiusY;
     private final Shader mInputShader;
+    private final TileMode mEdgeTreatment;
 
     private long mNativeInputShader = 0;
 
@@ -35,22 +37,42 @@
      * Create a {@link BlurShader} that blurs the contents of the optional input shader
      * with the specified radius along the x and y axis. If no input shader is provided
      * then all drawing commands issued with a {@link android.graphics.Paint} that this
+     * shader is installed in will be blurred.
+     *
+     * This uses a default {@link TileMode#DECAL} for edge treatment
+     *
+     * @param radiusX Radius of blur along the X axis
+     * @param radiusY Radius of blur along the Y axis
+     * @param inputShader Input shader that provides the content to be blurred
+     */
+    public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
+        this(radiusX, radiusY, inputShader, TileMode.DECAL);
+    }
+
+    /**
+     * Create a {@link BlurShader} that blurs the contents of the optional input shader
+     * with the specified radius along the x and y axis. If no input shader is provided
+     * then all drawing commands issued with a {@link android.graphics.Paint} that this
      * shader is installed in will be blurred
      * @param radiusX Radius of blur along the X axis
      * @param radiusY Radius of blur along the Y axis
      * @param inputShader Input shader that provides the content to be blurred
+     * @param edgeTreatment Policy for how to blur content near edges of the blur shader
      */
-    public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
+    public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader,
+            @NonNull TileMode edgeTreatment) {
         mRadiusX = radiusX;
         mRadiusY = radiusY;
         mInputShader = inputShader;
+        mEdgeTreatment = edgeTreatment;
     }
 
     /** @hide **/
     @Override
     protected long createNativeInstance(long nativeMatrix) {
         mNativeInputShader = mInputShader != null ? mInputShader.getNativeInstance() : 0;
-        return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader);
+        return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader,
+                mEdgeTreatment.nativeInt);
     }
 
     /** @hide **/
@@ -61,5 +83,5 @@
     }
 
     private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
-            long inputShader);
+            long inputShader, int edgeTreatment);
 }
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 8154ebf..d71ff11 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -95,7 +95,11 @@
          * repeat the shader's image horizontally and vertically, alternating
          * mirror images so that adjacent images always seam
          */
-        MIRROR  (2);
+        MIRROR(2),
+        /**
+         * Only draw within the original domain, return transparent-black everywhere else
+         */
+        DECAL(3);
 
         TileMode(int nativeInt) {
             this.nativeInt = nativeInt;
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index b09082e..cbae675 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -22,6 +22,8 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
+import android.graphics.Paint;
+import android.graphics.RectF;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
 import android.util.TypedValue;
@@ -29,6 +31,7 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -63,6 +66,7 @@
 
         private @Nullable ByteBuffer mBuffer;
         private @Nullable File mFile;
+        private @Nullable Font mFont;
         private @NonNull String mLocaleList = "";
         private @IntRange(from = -1, to = 1000) int mWeight = NOT_SPECIFIED;
         private @IntRange(from = -1, to = 1) int mItalic = NOT_SPECIFIED;
@@ -204,6 +208,22 @@
         }
 
         /**
+         * Constructs a builder from existing Font instance.
+         *
+         * @param font the font instance.
+         */
+        public Builder(@NonNull Font font) {
+            mFont = font;
+            // Copies all parameters as a default value.
+            mBuffer = font.getBuffer();
+            mWeight = font.getStyle().getWeight();
+            mItalic = font.getStyle().getSlant();
+            mAxes = font.getAxes();
+            mFile = font.getFile();
+            mTtcIndex = font.getTtcIndex();
+        }
+
+        /**
          * Creates a buffer containing font data using the assetManager and other
          * provided inputs.
          *
@@ -430,8 +450,13 @@
             }
             final ByteBuffer readonlyBuffer = mBuffer.asReadOnlyBuffer();
             final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
-            final long ptr = nBuild(builderPtr, readonlyBuffer, filePath, mWeight, italic,
-                    mTtcIndex);
+
+            long ptr;
+            if (mFont == null) {
+                ptr = nBuild(builderPtr, readonlyBuffer, filePath, mWeight, italic, mTtcIndex);
+            } else {
+                ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
+            }
             final Font font = new Font(ptr, readonlyBuffer, mFile,
                     new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList);
             sFontRegistry.registerNativeAllocation(font, ptr);
@@ -449,6 +474,10 @@
                 boolean italic, int ttcIndex);
         @CriticalNative
         private static native long nGetReleaseNativeFont();
+
+        @FastNative
+        private static native long nClone(long fontPtr, long builderPtr, int weight,
+                boolean italic, int ttcIndex);
     }
 
     private final long mNativePtr;  // address of the shared ptr of minikin::Font
@@ -538,6 +567,40 @@
         return LocaleList.forLanguageTags(mLocaleList);
     }
 
+    /**
+     * Retrieve the glyph horizontal advance and bounding box.
+     *
+     * Note that {@link android.graphics.Typeface} in {@link android.graphics.Paint} is ignored.
+     *
+     * @param glyphId a glyph ID
+     * @param paint a paint object used for resolving glyph style
+     * @param rect a nullable destination object. If null is passed, this function just return the
+     *             horizontal advance. If non-null is passed, this function fills bounding box
+     *             information to this object.
+     * @return the amount of horizontal advance in pixels
+     */
+    public float getGlyphBounds(@IntRange(from = 0) int glyphId, @NonNull Paint paint,
+            @Nullable RectF rect) {
+        return nGetGlyphBounds(mNativePtr, glyphId, paint.getNativeInstance(), rect);
+    }
+
+    /**
+     * Retrieve the font metrics information.
+     *
+     * Note that {@link android.graphics.Typeface} in {@link android.graphics.Paint} is ignored.
+     *
+     * @param paint a paint object used for retrieving font metrics.
+     * @param metrics a nullable destination object. If null is passed, this function only retrieve
+     *                recommended interline spacing. If non-null is passed, this function fills to
+     *                font metrics to it.
+     *
+     * @see Paint#getFontMetrics()
+     * @see Paint#getFontMetricsInt()
+     */
+    public void getMetrics(@NonNull Paint paint, @Nullable Paint.FontMetrics metrics) {
+        nGetFontMetrics(mNativePtr, paint.getNativeInstance(), metrics);
+    }
+
     /** @hide */
     public long getNativePtr() {
         return mNativePtr;
@@ -573,4 +636,10 @@
             + ", buffer=" + mBuffer
             + "}";
     }
+
+    @FastNative
+    private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
+
+    @FastNative
+    private static native float nGetFontMetrics(long font, long paint, Paint.FontMetrics metrics);
 }
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index c232d13..bb93e66 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -5,3 +5,6 @@
 reed@google.com
 scroggo@google.com
 stani@google.com
+
+# For text, e.g. Typeface, Font, Minikin, etc.
+nona@google.com
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a6137b0..0e338f3 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -33,8 +33,7 @@
 MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
                                  std::string_view filePath, int ttcIndex,
                                  const std::vector<minikin::FontVariation>& axes)
-        : minikin::MinikinFont(typeface->uniqueID())
-        , mTypeface(std::move(typeface))
+        : mTypeface(std::move(typeface))
         , mFontData(fontData)
         , mFontSize(fontSize)
         , mTtcIndex(ttcIndex)
diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp
index ecbb55ec..77f46be 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -9,6 +9,7 @@
 #include "GraphicsJNI.h"
 
 #include "SkCanvas.h"
+#include "SkFontMetrics.h"
 #include "SkMath.h"
 #include "SkRegion.h"
 #include <cutils/ashmem.h>
@@ -228,6 +229,20 @@
 static jclass gTransferParameters_class;
 static jmethodID gTransferParameters_constructorMethodID;
 
+static jclass   gFontMetrics_class;
+static jfieldID gFontMetrics_top;
+static jfieldID gFontMetrics_ascent;
+static jfieldID gFontMetrics_descent;
+static jfieldID gFontMetrics_bottom;
+static jfieldID gFontMetrics_leading;
+
+static jclass   gFontMetricsInt_class;
+static jfieldID gFontMetricsInt_top;
+static jfieldID gFontMetricsInt_ascent;
+static jfieldID gFontMetricsInt_descent;
+static jfieldID gFontMetricsInt_bottom;
+static jfieldID gFontMetricsInt_leading;
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
@@ -468,6 +483,32 @@
     return r;
 }
 
+void GraphicsJNI::set_metrics(JNIEnv* env, jobject metrics, const SkFontMetrics& skmetrics) {
+    if (metrics == nullptr) return;
+    SkASSERT(env->IsInstanceOf(metrics, gFontMetrics_class));
+    env->SetFloatField(metrics, gFontMetrics_top, SkScalarToFloat(skmetrics.fTop));
+    env->SetFloatField(metrics, gFontMetrics_ascent, SkScalarToFloat(skmetrics.fAscent));
+    env->SetFloatField(metrics, gFontMetrics_descent, SkScalarToFloat(skmetrics.fDescent));
+    env->SetFloatField(metrics, gFontMetrics_bottom, SkScalarToFloat(skmetrics.fBottom));
+    env->SetFloatField(metrics, gFontMetrics_leading, SkScalarToFloat(skmetrics.fLeading));
+}
+
+int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetrics& skmetrics) {
+    int ascent = SkScalarRoundToInt(skmetrics.fAscent);
+    int descent = SkScalarRoundToInt(skmetrics.fDescent);
+    int leading = SkScalarRoundToInt(skmetrics.fLeading);
+
+    if (metrics) {
+        SkASSERT(env->IsInstanceOf(metrics, gFontMetricsInt_class));
+        env->SetIntField(metrics, gFontMetricsInt_top, SkScalarFloorToInt(skmetrics.fTop));
+        env->SetIntField(metrics, gFontMetricsInt_ascent, ascent);
+        env->SetIntField(metrics, gFontMetricsInt_descent, descent);
+        env->SetIntField(metrics, gFontMetricsInt_bottom, SkScalarCeilToInt(skmetrics.fBottom));
+        env->SetIntField(metrics, gFontMetricsInt_leading, leading);
+    }
+    return descent - ascent + leading;
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, skia::BitmapRegionDecoder* bitmap)
@@ -764,5 +805,23 @@
     gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
             "<init>", "(DDDDDDD)V");
 
+    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
+    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
+
+    gFontMetrics_top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
+    gFontMetrics_ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
+    gFontMetrics_descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
+    gFontMetrics_bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
+    gFontMetrics_leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
+
+    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
+    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
+
+    gFontMetricsInt_top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
+    gFontMetricsInt_ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
+    gFontMetricsInt_descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
+    gFontMetricsInt_bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
+    gFontMetricsInt_leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
+
     return 0;
 }
diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h
index 79ab617..541d5a5 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -18,6 +18,7 @@
 #include "graphics_jni_helpers.h"
 
 class SkCanvas;
+struct SkFontMetrics;
 
 namespace android {
 namespace skia {
@@ -85,6 +86,17 @@
                                      bool* isHardware);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
+    /**
+     * Set SkFontMetrics to Java Paint.FontMetrics.
+     * Do nothing if metrics is nullptr.
+     */
+    static void set_metrics(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics);
+    /**
+     * Set SkFontMetrics to Java Paint.FontMetricsInt and return recommended interline space.
+     * Do nothing if metrics is nullptr.
+     */
+    static int set_metrics_int(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics);
+
     /*
      *  LegacyBitmapConfig is the old enum in Skia that matched the enum int values
      *  in Bitmap.Config. Skia no longer supports this config, but has replaced it
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index 554674a..d275659 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -59,20 +59,6 @@
 
 namespace android {
 
-struct JMetricsID {
-    jfieldID    top;
-    jfieldID    ascent;
-    jfieldID    descent;
-    jfieldID    bottom;
-    jfieldID    leading;
-};
-
-static jclass   gFontMetrics_class;
-static JMetricsID gFontMetrics_fieldID;
-
-static jclass   gFontMetricsInt_class;
-static JMetricsID gFontMetricsInt_fieldID;
-
 static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count,
                            const SkPoint pos[], SkPath* dst) {
     dst->reset();
@@ -618,35 +604,14 @@
     static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
         SkFontMetrics metrics;
         SkScalar spacing = getMetricsInternal(paintHandle, &metrics);
-
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
-            env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
-        }
+        GraphicsJNI::set_metrics(env, metricsObj, metrics);
         return SkScalarToFloat(spacing);
     }
 
     static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle, jobject metricsObj) {
         SkFontMetrics metrics;
-
         getMetricsInternal(paintHandle, &metrics);
-        int ascent = SkScalarRoundToInt(metrics.fAscent);
-        int descent = SkScalarRoundToInt(metrics.fDescent);
-        int leading = SkScalarRoundToInt(metrics.fLeading);
-
-        if (metricsObj) {
-            SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
-            env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
-        }
-        return descent - ascent + leading;
+        return GraphicsJNI::set_metrics_int(env, metricsObj, metrics);
     }
 
 
@@ -1137,24 +1102,6 @@
 };
 
 int register_android_graphics_Paint(JNIEnv* env) {
-    gFontMetrics_class = FindClassOrDie(env, "android/graphics/Paint$FontMetrics");
-    gFontMetrics_class = MakeGlobalRefOrDie(env, gFontMetrics_class);
-
-    gFontMetrics_fieldID.top = GetFieldIDOrDie(env, gFontMetrics_class, "top", "F");
-    gFontMetrics_fieldID.ascent = GetFieldIDOrDie(env, gFontMetrics_class, "ascent", "F");
-    gFontMetrics_fieldID.descent = GetFieldIDOrDie(env, gFontMetrics_class, "descent", "F");
-    gFontMetrics_fieldID.bottom = GetFieldIDOrDie(env, gFontMetrics_class, "bottom", "F");
-    gFontMetrics_fieldID.leading = GetFieldIDOrDie(env, gFontMetrics_class, "leading", "F");
-
-    gFontMetricsInt_class = FindClassOrDie(env, "android/graphics/Paint$FontMetricsInt");
-    gFontMetricsInt_class = MakeGlobalRefOrDie(env, gFontMetricsInt_class);
-
-    gFontMetricsInt_fieldID.top = GetFieldIDOrDie(env, gFontMetricsInt_class, "top", "I");
-    gFontMetricsInt_fieldID.ascent = GetFieldIDOrDie(env, gFontMetricsInt_class, "ascent", "I");
-    gFontMetricsInt_fieldID.descent = GetFieldIDOrDie(env, gFontMetricsInt_class, "descent", "I");
-    gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
-    gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
-
     return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
 }
 
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 7cb7723..0a194f9 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -224,7 +224,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
-        jfloat sigmaY, jlong shaderHandle) {
+        jfloat sigmaY, jlong shaderHandle, jint edgeTreatment) {
     auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
     auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
 
@@ -232,6 +232,7 @@
                 sigmaX,
                 sigmaY,
                 inputShader,
+                static_cast<SkTileMode>(edgeTreatment),
                 matrix
             );
     return reinterpret_cast<jlong>(blurShader);
@@ -291,7 +292,7 @@
 };
 
 static const JNINativeMethod gBlurShaderMethods[] = {
-    { "nativeCreate",      "(JFFJ)J", (void*)BlurShader_create }
+    { "nativeCreate",      "(JFFJI)J", (void*)BlurShader_create }
 };
 
 static const JNINativeMethod gLinearGradientMethods[] = {
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 996cdce..bcdb4f5 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "Minikin"
 
 #include "SkData.h"
+#include "SkFont.h"
+#include "SkFontMetrics.h"
 #include "SkFontMgr.h"
 #include "SkRefCnt.h"
 #include "SkTypeface.h"
@@ -27,6 +29,7 @@
 #include "FontUtils.h"
 
 #include <hwui/MinikinSkia.h>
+#include <hwui/Paint.h>
 #include <hwui/Typeface.h>
 #include <minikin/FontFamily.h>
 #include <ui/FatVector.h>
@@ -120,6 +123,36 @@
     return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
 }
 
+// Fast Native
+static jlong Font_Builder_clone(JNIEnv* env, jobject clazz, jlong fontPtr, jlong builderPtr,
+                                jint weight, jboolean italic, jint ttcIndex) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontPtr);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+    std::unique_ptr<NativeFontBuilder> builder(toBuilder(builderPtr));
+
+    // Reconstruct SkTypeface with different arguments from existing SkTypeface.
+    FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
+    for (const auto& axis : builder->axes) {
+        skVariation.push_back({axis.axisTag, axis.value});
+    }
+    SkFontArguments args;
+    args.setCollectionIndex(ttcIndex);
+    args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
+
+    sk_sp<SkTypeface> newTypeface = minikinSkia->GetSkTypeface()->makeClone(args);
+
+    std::shared_ptr<minikin::MinikinFont> newMinikinFont = std::make_shared<MinikinFontSkia>(
+        std::move(newTypeface),
+        minikinSkia->GetFontData(),
+        minikinSkia->GetFontSize(),
+        minikinSkia->getFilePath(),
+        minikinSkia->GetFontIndex(),
+        builder->axes);
+    minikin::Font newFont = minikin::Font::Builder(newMinikinFont).setWeight(weight)
+              .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
+    return reinterpret_cast<jlong>(new FontWrapper(std::move(newFont)));
+}
+
 // Critical Native
 static jlong Font_Builder_getReleaseNativeFont(CRITICAL_JNI_PARAMS) {
     return reinterpret_cast<jlong>(releaseFont);
@@ -127,16 +160,64 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+// Fast Native
+static jfloat Font_getGlyphBounds(JNIEnv* env, jobject, jlong fontHandle, jint glyphId,
+                                  jlong paintHandle, jobject rect) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+
+    SkFont* skFont = &paint->getSkFont();
+    // We don't use populateSkFont since it is designed to be used for layout result with addressing
+    // auto fake-bolding.
+    skFont->setTypeface(minikinSkia->RefSkTypeface());
+
+    uint16_t glyph16 = glyphId;
+    SkRect skBounds;
+    SkScalar skWidth;
+    skFont->getWidthsBounds(&glyph16, 1, &skWidth, &skBounds, nullptr);
+    GraphicsJNI::rect_to_jrectf(skBounds, env, rect);
+    return SkScalarToFloat(skWidth);
+}
+
+// Fast Native
+static jfloat Font_getFontMetrics(JNIEnv* env, jobject, jlong fontHandle, jlong paintHandle,
+                                  jobject metricsObj) {
+    FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->font.typeface().get());
+    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+
+    SkFont* skFont = &paint->getSkFont();
+    // We don't use populateSkFont since it is designed to be used for layout result with addressing
+    // auto fake-bolding.
+    skFont->setTypeface(minikinSkia->RefSkTypeface());
+
+    SkFontMetrics metrics;
+    SkScalar spacing = skFont->getMetrics(&metrics);
+    GraphicsJNI::set_metrics(env, metricsObj, metrics);
+    return spacing;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 static const JNINativeMethod gFontBuilderMethods[] = {
     { "nInitBuilder", "()J", (void*) Font_Builder_initBuilder },
     { "nAddAxis", "(JIF)V", (void*) Font_Builder_addAxis },
     { "nBuild", "(JLjava/nio/ByteBuffer;Ljava/lang/String;IZI)J", (void*) Font_Builder_build },
+    { "nClone", "(JJIZI)J", (void*) Font_Builder_clone },
     { "nGetReleaseNativeFont", "()J", (void*) Font_Builder_getReleaseNativeFont },
 };
 
+static const JNINativeMethod gFontMethods[] = {
+    { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
+    { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
+};
+
 int register_android_graphics_fonts_Font(JNIEnv* env) {
     return RegisterMethodsOrDie(env, "android/graphics/fonts/Font$Builder", gFontBuilderMethods,
-            NELEM(gFontBuilderMethods));
+            NELEM(gFontBuilderMethods)) +
+            RegisterMethodsOrDie(env, "android/graphics/fonts/Font", gFontMethods,
+            NELEM(gFontMethods));
 }
 
 }
diff --git a/libs/hwui/shader/BlurShader.cpp b/libs/hwui/shader/BlurShader.cpp
index fa10be1..2abd871 100644
--- a/libs/hwui/shader/BlurShader.cpp
+++ b/libs/hwui/shader/BlurShader.cpp
@@ -20,13 +20,14 @@
 #include "utils/Blur.h"
 
 namespace android::uirenderer {
-BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix)
+BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, SkTileMode edgeTreatment,
+        const SkMatrix* matrix)
     : Shader(matrix)
     , skImageFilter(
             SkImageFilters::Blur(
                     Blur::convertRadiusToSigma(radiusX),
                     Blur::convertRadiusToSigma(radiusY),
-                    SkTileMode::kClamp,
+                    edgeTreatment,
                     inputShader ? inputShader->asSkImageFilter() : nullptr,
                     nullptr)
             ) { }
diff --git a/libs/hwui/shader/BlurShader.h b/libs/hwui/shader/BlurShader.h
index 9eb22bd..60a1589 100644
--- a/libs/hwui/shader/BlurShader.h
+++ b/libs/hwui/shader/BlurShader.h
@@ -30,8 +30,12 @@
      *
      * This will blur the contents of the provided input shader if it is non-null, otherwise
      * the source bitmap will be blurred instead.
+     *
+     * The edge treatment parameter determines how content near the edges of the source is to
+     * participate in the blur
      */
-    BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix);
+    BlurShader(float radiusX, float radiusY, Shader* inputShader, SkTileMode edgeTreatment,
+            const SkMatrix* matrix);
     ~BlurShader() override;
 protected:
     sk_sp<SkImageFilter> makeSkImageFilter() override;
diff --git a/media/Android.bp b/media/Android.bp
index 8895b3a..828707b 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,85 +1,52 @@
 aidl_interface {
     name: "audio_common-aidl",
     unstable: true,
-    local_include_dir: "java",
+    local_include_dir: "aidl",
     srcs: [
-        "java/android/media/audio/common/AudioChannelMask.aidl",
-        "java/android/media/audio/common/AudioConfig.aidl",
-        "java/android/media/audio/common/AudioFormat.aidl",
-        "java/android/media/audio/common/AudioOffloadInfo.aidl",
-        "java/android/media/audio/common/AudioStreamType.aidl",
-        "java/android/media/audio/common/AudioUsage.aidl",
+        "aidl/android/media/audio/common/AudioChannelMask.aidl",
+        "aidl/android/media/audio/common/AudioConfig.aidl",
+        "aidl/android/media/audio/common/AudioFormat.aidl",
+        "aidl/android/media/audio/common/AudioOffloadInfo.aidl",
+        "aidl/android/media/audio/common/AudioStreamType.aidl",
+        "aidl/android/media/audio/common/AudioUsage.aidl",
     ],
-    backend:
-    {
-        cpp: {
-            enabled: true,
-        },
-        java: {
-            // Already generated as part of the entire media java library.
-            enabled: false,
-        },
-    },
 }
 
 aidl_interface {
     name: "media_permission-aidl",
     unstable: true,
-    local_include_dir: "java",
+    local_include_dir: "aidl",
     srcs: [
-        "java/android/media/permission/Identity.aidl",
+        "aidl/android/media/permission/Identity.aidl",
     ],
-    backend:
-    {
-        cpp: {
-            enabled: true,
-        },
-        java: {
-            // Already generated as part of the entire media java library.
-            enabled: false,
-        },
-    },
 }
 
 aidl_interface {
     name: "soundtrigger_middleware-aidl",
     unstable: true,
-    local_include_dir: "java",
+    local_include_dir: "aidl",
     srcs: [
-        "java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl",
-        "java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
-        "java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
-        "java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
-        "java/android/media/soundtrigger_middleware/ModelParameter.aidl",
-        "java/android/media/soundtrigger_middleware/ModelParameterRange.aidl",
-        "java/android/media/soundtrigger_middleware/Phrase.aidl",
-        "java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl",
-        "java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl",
-        "java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl",
-        "java/android/media/soundtrigger_middleware/RecognitionConfig.aidl",
-        "java/android/media/soundtrigger_middleware/RecognitionEvent.aidl",
-        "java/android/media/soundtrigger_middleware/RecognitionMode.aidl",
-        "java/android/media/soundtrigger_middleware/RecognitionStatus.aidl",
-        "java/android/media/soundtrigger_middleware/SoundModel.aidl",
-        "java/android/media/soundtrigger_middleware/SoundModelType.aidl",
-        "java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
-        "java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl",
-        "java/android/media/soundtrigger_middleware/Status.aidl",
+        "aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl",
+        "aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl",
+        "aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
+        "aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
+        "aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
+        "aidl/android/media/soundtrigger_middleware/ModelParameter.aidl",
+        "aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl",
+        "aidl/android/media/soundtrigger_middleware/Phrase.aidl",
+        "aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl",
+        "aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl",
+        "aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl",
+        "aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl",
+        "aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl",
+        "aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl",
+        "aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl",
+        "aidl/android/media/soundtrigger_middleware/SoundModel.aidl",
+        "aidl/android/media/soundtrigger_middleware/SoundModelType.aidl",
+        "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
+        "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl",
+        "aidl/android/media/soundtrigger_middleware/Status.aidl",
     ],
-    backend:
-    {
-        cpp: {
-            enabled: true,
-        },
-        java: {
-            // Already generated as part of the entire media java library.
-            enabled: false,
-        },
-        ndk: {
-            // Not currently needed, and disabled because of b/146172425
-            enabled: false,
-        },
-    },
     imports: [
         "audio_common-aidl",
         "media_permission-aidl",
diff --git a/media/java/android/media/audio/common/AudioChannelMask.aidl b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioChannelMask.aidl
rename to media/aidl/android/media/audio/common/AudioChannelMask.aidl
diff --git a/media/java/android/media/audio/common/AudioConfig.aidl b/media/aidl/android/media/audio/common/AudioConfig.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioConfig.aidl
rename to media/aidl/android/media/audio/common/AudioConfig.aidl
diff --git a/media/java/android/media/audio/common/AudioFormat.aidl b/media/aidl/android/media/audio/common/AudioFormat.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioFormat.aidl
rename to media/aidl/android/media/audio/common/AudioFormat.aidl
diff --git a/media/java/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioOffloadInfo.aidl
rename to media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
diff --git a/media/java/android/media/audio/common/AudioStreamType.aidl b/media/aidl/android/media/audio/common/AudioStreamType.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioStreamType.aidl
rename to media/aidl/android/media/audio/common/AudioStreamType.aidl
diff --git a/media/java/android/media/audio/common/AudioUsage.aidl b/media/aidl/android/media/audio/common/AudioUsage.aidl
similarity index 100%
rename from media/java/android/media/audio/common/AudioUsage.aidl
rename to media/aidl/android/media/audio/common/AudioUsage.aidl
diff --git a/media/java/android/media/permission/Identity.aidl b/media/aidl/android/media/permission/Identity.aidl
similarity index 100%
rename from media/java/android/media/permission/Identity.aidl
rename to media/aidl/android/media/permission/Identity.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/AudioCapabilities.aidl b/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/AudioCapabilities.aidl
rename to media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl b/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ModelParameter.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ModelParameter.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ModelParameterRange.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/ModelParameterRange.aidl
rename to media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/OWNERS b/media/aidl/android/media/soundtrigger_middleware/OWNERS
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/OWNERS
rename to media/aidl/android/media/soundtrigger_middleware/OWNERS
diff --git a/media/java/android/media/soundtrigger_middleware/Phrase.aidl b/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/Phrase.aidl
rename to media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
rename to media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
rename to media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
rename to media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionConfig.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/RecognitionConfig.aidl
rename to media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
rename to media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionMode.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/RecognitionMode.aidl
rename to media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionStatus.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/RecognitionStatus.aidl
rename to media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
similarity index 94%
rename from media/java/android/media/soundtrigger_middleware/SoundModel.aidl
rename to media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
index 81d8291..cee3635 100644
--- a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
@@ -16,6 +16,7 @@
 package android.media.soundtrigger_middleware;
 
 import android.media.soundtrigger_middleware.SoundModelType;
+import android.os.ParcelFileDescriptor;
 
 /**
  * Base sound model descriptor. This struct can be extended for various specific types by way of
@@ -32,7 +33,7 @@
      * was build for */
     String vendorUuid;
     /** Opaque data transparent to Android framework */
-    FileDescriptor data;
+    ParcelFileDescriptor data;
     /** Size of the above data, in bytes. */
     int dataSize;
 }
diff --git a/media/java/android/media/soundtrigger_middleware/SoundModelType.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/SoundModelType.aidl
rename to media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
rename to media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
rename to media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/Status.aidl b/media/aidl/android/media/soundtrigger_middleware/Status.aidl
similarity index 100%
rename from media/java/android/media/soundtrigger_middleware/Status.aidl
rename to media/aidl/android/media/soundtrigger_middleware/Status.aidl
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e1e55c2..22b5ca5 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -96,8 +96,8 @@
     private Context mOriginalContext;
     private Context mApplicationContext;
     private long mVolumeKeyUpTime;
-    private final boolean mUseVolumeKeySounds;
-    private final boolean mUseFixedVolume;
+    private boolean mUseFixedVolumeInitialized;
+    private boolean mUseFixedVolume;
     private static final String TAG = "AudioManager";
     private static final boolean DEBUG = false;
     private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
@@ -711,8 +711,6 @@
      */
     @UnsupportedAppUsage
     public AudioManager() {
-        mUseVolumeKeySounds = true;
-        mUseFixedVolume = false;
     }
 
     /**
@@ -721,10 +719,6 @@
     @UnsupportedAppUsage
     public AudioManager(Context context) {
         setContext(context);
-        mUseVolumeKeySounds = getContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_useVolumeKeySounds);
-        mUseFixedVolume = getContext().getResources().getBoolean(
-                com.android.internal.R.bool.config_useFixedVolume);
     }
 
     private Context getContext() {
@@ -823,6 +817,18 @@
      * </ul>
      */
     public boolean isVolumeFixed() {
+        synchronized (this) {
+            try {
+                if (!mUseFixedVolumeInitialized) {
+                    mUseFixedVolume = getContext().getResources().getBoolean(
+                            com.android.internal.R.bool.config_useFixedVolume);
+                }
+            } catch (Exception e) {
+            } finally {
+                // only ever try once, so always consider initialized even if query failed
+                mUseFixedVolumeInitialized = true;
+            }
+        }
         return mUseFixedVolume;
     }
 
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ddc7db7..8845d69 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -31,7 +31,6 @@
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.os.Build;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -599,7 +598,6 @@
     private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
     private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
 
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     @GuardedBy("sFormatter")
     private static SimpleDateFormat sFormatter;
     @GuardedBy("sFormatterTz")
@@ -1446,18 +1444,17 @@
         sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256
     }
 
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mFilename;
     private FileDescriptor mSeekableFileDescriptor;
     private AssetManager.AssetInputStream mAssetInputStream;
     private boolean mIsInputStream;
     private int mMimeType;
     private boolean mIsExifDataOnly;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(publicAlternatives = "Use {@link #getAttribute(java.lang.String)} "
+            + "instead.")
     private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
     private Set<Integer> mHandledIfdOffsets = new HashSet<>(EXIF_TAGS.length);
     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private boolean mHasThumbnail;
     private boolean mHasThumbnailStrips;
     private boolean mAreThumbnailStripsConsecutive;
@@ -2409,11 +2406,8 @@
     }
 
     /**
-     * Returns parsed {@code DateTime} value, or -1 if unavailable or invalid.
-     * 
-     * @hide
+     * Returns parsed {@link #TAG_DATETIME} value, or -1 if unavailable or invalid.
      */
-    @UnsupportedAppUsage
     public @CurrentTimeMillisLong long getDateTime() {
         return parseDateTime(getAttribute(TAG_DATETIME),
                 getAttribute(TAG_SUBSEC_TIME),
@@ -2421,10 +2415,7 @@
     }
 
     /**
-     * Returns parsed {@code DateTimeDigitized} value, or -1 if unavailable or
-     * invalid.
-     *
-     * @hide
+     * Returns parsed {@link #TAG_DATETIME_DIGITIZED} value, or -1 if unavailable or invalid.
      */
     public @CurrentTimeMillisLong long getDateTimeDigitized() {
         return parseDateTime(getAttribute(TAG_DATETIME_DIGITIZED),
@@ -2433,12 +2424,8 @@
     }
 
     /**
-     * Returns parsed {@code DateTimeOriginal} value, or -1 if unavailable or
-     * invalid.
-     *
-     * @hide
+     * Returns parsed {@link #TAG_DATETIME_ORIGINAL} value, or -1 if unavailable or invalid.
      */
-    @UnsupportedAppUsage
     public @CurrentTimeMillisLong long getDateTimeOriginal() {
         return parseDateTime(getAttribute(TAG_DATETIME_ORIGINAL),
                 getAttribute(TAG_SUBSEC_TIME_ORIGINAL),
@@ -2490,9 +2477,7 @@
     /**
      * Returns number of milliseconds since Jan. 1, 1970, midnight UTC.
      * Returns -1 if the date time information if not available.
-     * @hide
      */
-    @UnsupportedAppUsage
     public long getGpsDateTime() {
         String date = getAttribute(TAG_GPS_DATESTAMP);
         String time = getAttribute(TAG_GPS_TIMESTAMP);
@@ -2518,7 +2503,6 @@
     }
 
     /** {@hide} */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static float convertRationalLatLonToFloat(String rationalString, String ref) {
         try {
             String [] parts = rationalString.split(",");
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 755bbfb..1a49b85 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -20,10 +20,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.AbstractSet;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -436,6 +438,52 @@
     public static final String KEY_CAPTURE_RATE = "capture-rate";
 
     /**
+     * A key for retrieving the slow-motion marker information associated with a video track.
+     * <p>
+     * The associated value is a ByteBuffer in {@link ByteOrder#BIG_ENDIAN}
+     * (networking order) of the following format:
+     * </p>
+     * <pre class="prettyprint">
+     *     float(32) playbackRate;
+     *     unsigned int(32) numMarkers;
+     *     for (i = 0;i < numMarkers; i++) {
+     *         int(64) timestampUs;
+     *         float(32) speedRatio;
+     *     }</pre>
+     * The meaning of each field is as follows:
+     * <table border="1" width="90%" align="center" cellpadding="5">
+     *     <tbody>
+     *     <tr>
+     *         <td>playbackRate</td>
+     *         <td>The frame rate at which the playback should happen (or the flattened
+     *             clip should be).</td>
+     *     </tr>
+     *     <tr>
+     *         <td>numMarkers</td>
+     *         <td>The number of slow-motion markers that follows.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>timestampUs</td>
+     *         <td>The starting point of a new segment.</td>
+     *     </tr>
+     *     <tr>
+     *         <td>speedRatio</td>
+     *         <td>The playback speed for that segment. The playback speed is a floating
+     *             point number, indicating how fast the time progresses relative to that
+     *             written in the container. (Eg. 4.0 means time goes 4x as fast, which
+     *             makes 30fps become 120fps.)</td>
+     *     </tr>
+     * </table>
+     * <p>
+     * The following constraints apply to the timestampUs of the markers:
+     * </p>
+     * <li>The timestampUs shall be monotonically increasing.</li>
+     * <li>The timestampUs shall fall within the time span of the video track.</li>
+     * <li>The first timestampUs should match that of the first video sample.</li>
+     */
+    public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
+
+    /**
      * A key describing the frequency of key frames expressed in seconds between key frames.
      * <p>
      * This key is used by video encoders.
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index e092411..21376bb 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -83,13 +83,13 @@
 
  <pre class=prettyprint>
  TranscodingRequest request =
-     new TranscodingRequest.Builder()
-         .setSourceUri(srcUri)
-         .setDestinationUri(dstUri)
-         .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
-         .setPriority(REALTIME)
-         .setVideoTrackFormat(videoFormat)
-         .build();
+    new TranscodingRequest.Builder()
+        .setSourceUri(srcUri)
+        .setDestinationUri(dstUri)
+        .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+        .setPriority(REALTIME)
+        .setVideoTrackFormat(videoFormat)
+        .build();
  }</pre>
 
  TODO(hkuang): Add architecture diagram showing the transcoding service and api.
@@ -498,6 +498,20 @@
         /** Uri of the destination media file. */
         private @NonNull Uri mDestinationUri;
 
+        /**
+         *  The UID of the client that the TranscodingRequest is for. Only privileged caller could
+         *  set this Uid as only they could do the transcoding on behalf of the client.
+         *  -1 means not available.
+         */
+        private int mClientUid = -1;
+
+        /**
+         *  The Pid of the client that the TranscodingRequest is for. Only privileged caller could
+         *  set this Uid as only they could do the transcoding on behalf of the client.
+         *  -1 means not available.
+         */
+        private int mClientPid = -1;
+
         /** Type of the transcoding. */
         private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
 
@@ -534,6 +548,8 @@
         private TranscodingRequest(Builder b) {
             mSourceUri = b.mSourceUri;
             mDestinationUri = b.mDestinationUri;
+            mClientUid = b.mClientUid;
+            mClientPid = b.mClientPid;
             mPriority = b.mPriority;
             mType = b.mType;
             mVideoTrackFormat = b.mVideoTrackFormat;
@@ -554,6 +570,16 @@
             return mSourceUri;
         }
 
+        /** Return the UID of the client that this request is for. -1 means not available. */
+        public int getClientUid() {
+            return mClientUid;
+        }
+
+        /** Return the PID of the client that this request is for. -1 means not available. */
+        public int getClientPid() {
+            return mClientPid;
+        }
+
         /** Return destination uri of the transcoding. */
         @NonNull
         public Uri getDestinationUri() {
@@ -592,6 +618,8 @@
             parcel.transcodingType = mType;
             parcel.sourceFilePath = mSourceUri.toString();
             parcel.destinationFilePath = mDestinationUri.toString();
+            parcel.clientUid = mClientUid;
+            parcel.clientPid = mClientPid;
             parcel.requestedVideoTrackFormat = convertToVideoTrackFormat(mVideoTrackFormat);
             if (mTestConfig != null) {
                 parcel.isForTesting = true;
@@ -667,6 +695,8 @@
         public static final class Builder {
             private @NonNull Uri mSourceUri;
             private @NonNull Uri mDestinationUri;
+            private int mClientUid = -1;
+            private int mClientPid = -1;
             private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
             private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN;
             private @Nullable MediaFormat mVideoTrackFormat;
@@ -710,6 +740,38 @@
             }
 
             /**
+             * Specify the UID of the client that this request is for.
+             * @param uid client Uid.
+             * @return The same builder instance.
+             * @throws IllegalArgumentException if uid is invalid.
+             * TODO(hkuang): Check the permission if it is allowed.
+             */
+            @NonNull
+            public Builder setClientUid(int uid) {
+                if (uid <= 0) {
+                    throw new IllegalArgumentException("Invalid Uid");
+                }
+                mClientUid = uid;
+                return this;
+            }
+
+            /**
+             * Specify the PID of the client that this request is for.
+             * @param pid client Pid.
+             * @return The same builder instance.
+             * @throws IllegalArgumentException if pid is invalid.
+             * TODO(hkuang): Check the permission if it is allowed.
+             */
+            @NonNull
+            public Builder setClientPid(int pid) {
+                if (pid <= 0) {
+                    throw new IllegalArgumentException("Invalid pid");
+                }
+                mClientPid = pid;
+                return this;
+            }
+
+            /**
              * Specifies the priority of the transcoding.
              *
              * @param priority Must be one of the {@code PRIORITY_*}
@@ -1225,6 +1287,50 @@
             }
         }
 
+        @Override
+        public String toString() {
+            String result;
+            String status;
+
+            switch (mResult) {
+                case RESULT_NONE:
+                    result = "RESULT_NONE";
+                    break;
+                case RESULT_SUCCESS:
+                    result = "RESULT_SUCCESS";
+                    break;
+                case RESULT_ERROR:
+                    result = "RESULT_ERROR";
+                    break;
+                case RESULT_CANCELED:
+                    result = "RESULT_CANCELED";
+                    break;
+                default:
+                    result = String.valueOf(mResult);
+                    break;
+            }
+
+            switch (mStatus) {
+                case STATUS_PENDING:
+                    status = "STATUS_PENDING";
+                    break;
+                case STATUS_PAUSED:
+                    status = "STATUS_PAUSED";
+                    break;
+                case STATUS_RUNNING:
+                    status = "STATUS_RUNNING";
+                    break;
+                case STATUS_FINISHED:
+                    status = "STATUS_FINISHED";
+                    break;
+                default:
+                    status = String.valueOf(mStatus);
+                    break;
+            }
+            return String.format(" Job: {id: %d, status: %s, result: %s, progress: %d}",
+                    mJobId, status, result, mProgress);
+        }
+
         private void updateProgress(int newProgress) {
             synchronized (mLock) {
                 mProgress = newProgress;
@@ -1275,6 +1381,8 @@
         // Converts the request to TranscodingRequestParcel.
         TranscodingRequestParcel requestParcel = transcodingRequest.writeToParcel();
 
+        Log.i(TAG, "Getting transcoding request " + transcodingRequest.getSourceUri());
+
         // Submits the request to MediaTranscoding service.
         try {
             TranscodingJobParcel jobParcel = new TranscodingJobParcel();
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 011e835..b662901 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -184,7 +184,7 @@
                 boolean bound = false;
                 try {
                     bound = mContext.bindService(intent, mServiceConnection,
-                            Context.BIND_AUTO_CREATE);
+                            Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES);
                 } catch (Exception ex) {
                     Log.e(TAG, "Failed binding to service " + mServiceComponent);
                 }
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 33d6d64..21ed840 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -203,6 +203,42 @@
     }
 
     /**
+     * Verify that setting invalid pid will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingWithInvalidClientPid() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setDestinationUri(mDestinationUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setClientPid(-1)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that setting invalid uid will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingWithInvalidClientUid() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setDestinationUri(mDestinationUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setClientUid(-1)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
      * Verify that setting null source uri will throw exception.
      */
     @Test
@@ -425,16 +461,24 @@
         MediaFormat videoTrackFormat = resolver.resolveVideoFormat();
         assertNotNull(videoTrackFormat);
 
+        int pid = android.os.Process.myPid();
+        int uid = android.os.Process.myUid();
+
         TranscodingRequest request =
                 new TranscodingRequest.Builder()
                         .setSourceUri(mSourceHEVCVideoUri)
                         .setDestinationUri(destinationUri)
                         .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                        .setClientPid(pid)
+                        .setClientUid(uid)
                         .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
                         .setVideoTrackFormat(videoTrackFormat)
                         .build();
         Executor listenerExecutor = Executors.newSingleThreadExecutor();
 
+        assertEquals(pid, request.getClientPid());
+        assertEquals(uid, request.getClientUid());
+
         Log.i(TAG, "transcoding to " + videoTrackFormat);
 
         TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp
new file mode 100644
index 0000000..4037781
--- /dev/null
+++ b/non-updatable-api/Android.bp
@@ -0,0 +1,35 @@
+// 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 {
+    default_visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "non-updatable-current.txt",
+    srcs: ["current.txt"],
+    visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+    name: "non-updatable-system-current.txt",
+    srcs: ["system-current.txt"],
+    visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+    name: "non-updatable-module-lib-current.txt",
+    srcs: ["module-lib-current.txt"],
+    visibility: ["//frameworks/base/api"],
+}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index bcc239f..d46f1d1 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -14292,6 +14292,7 @@
 
   public final class BlurShader extends android.graphics.Shader {
     ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+    ctor public BlurShader(float, float, @Nullable android.graphics.Shader, @NonNull android.graphics.Shader.TileMode);
   }
 
   public class Camera {
@@ -15626,6 +15627,7 @@
 
   public enum Shader.TileMode {
     enum_constant public static final android.graphics.Shader.TileMode CLAMP;
+    enum_constant public static final android.graphics.Shader.TileMode DECAL;
     enum_constant public static final android.graphics.Shader.TileMode MIRROR;
     enum_constant public static final android.graphics.Shader.TileMode REPEAT;
   }
@@ -16369,7 +16371,9 @@
     method @Nullable public android.graphics.fonts.FontVariationAxis[] getAxes();
     method @NonNull public java.nio.ByteBuffer getBuffer();
     method @Nullable public java.io.File getFile();
+    method public float getGlyphBounds(@IntRange(from=0) int, @NonNull android.graphics.Paint, @Nullable android.graphics.RectF);
     method @NonNull public android.os.LocaleList getLocaleList();
+    method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
     method @NonNull public android.graphics.fonts.FontStyle getStyle();
     method @IntRange(from=0) public int getTtcIndex();
   }
@@ -16381,6 +16385,7 @@
     ctor public Font.Builder(@NonNull android.os.ParcelFileDescriptor, @IntRange(from=0) long, @IntRange(from=0xffffffff) long);
     ctor public Font.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
     ctor public Font.Builder(@NonNull android.content.res.Resources, int);
+    ctor public Font.Builder(@NonNull android.graphics.fonts.Font);
     method @NonNull public android.graphics.fonts.Font build() throws java.io.IOException;
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable String);
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
@@ -24909,6 +24914,10 @@
     method public double getAttributeDouble(@NonNull String, double);
     method public int getAttributeInt(@NonNull String, int);
     method @Nullable public long[] getAttributeRange(@NonNull String);
+    method public long getDateTime();
+    method public long getDateTimeDigitized();
+    method public long getDateTimeOriginal();
+    method public long getGpsDateTime();
     method public boolean getLatLong(float[]);
     method public byte[] getThumbnail();
     method public android.graphics.Bitmap getThumbnailBitmap();
@@ -26255,6 +26264,7 @@
     field public static final String KEY_ROTATION = "rotation-degrees";
     field public static final String KEY_SAMPLE_RATE = "sample-rate";
     field public static final String KEY_SLICE_HEIGHT = "slice-height";
+    field public static final String KEY_SLOW_MOTION_MARKERS = "slow-motion-markers";
     field public static final String KEY_STRIDE = "stride";
     field public static final String KEY_TEMPORAL_LAYERING = "ts-schema";
     field public static final String KEY_TILE_HEIGHT = "tile-height";
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 10fe058..e27ca09 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4339,6 +4339,8 @@
   }
 
   public static final class MediaTranscodeManager.TranscodingRequest {
+    method public int getClientPid();
+    method public int getClientUid();
     method @NonNull public android.net.Uri getDestinationUri();
     method public int getPriority();
     method @NonNull public android.net.Uri getSourceUri();
@@ -4349,6 +4351,8 @@
   public static final class MediaTranscodeManager.TranscodingRequest.Builder {
     ctor public MediaTranscodeManager.TranscodingRequest.Builder();
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
     method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index 2c97889..e7295aa 100644
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
@@ -25,7 +25,8 @@
     <ViewStub android:id="@+id/notification_panel_stub"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
-              android:layout="@layout/notification_panel_container"/>
+              android:layout="@layout/notification_panel_container"
+              android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/>
 
     <ViewStub android:id="@+id/keyguard_stub"
               android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 28b8ead..fe060ac 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -207,6 +207,12 @@
     <dimen name="car_navigation_bar_width">760dp</dimen>
     <dimen name="car_left_navigation_bar_width">96dp</dimen>
     <dimen name="car_right_navigation_bar_width">96dp</dimen>
+    <!-- In order to change the height of the bottom nav bar, overlay navigation_bar_height in
+         frameworks/base/core/res/res instead. -->
+    <dimen name="car_bottom_navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
+    <!-- In order to change the height of the top nav bar, overlay status_bar_height in
+         frameworks/base/core/res/res instead. -->
+    <dimen name="car_top_navigation_bar_height">@*android:dimen/status_bar_height</dimen>
 
     <dimen name="car_user_switcher_container_height">420dp</dimen>
     <!-- This must be the negative of car_user_switcher_container_height for the animation. -->
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index 078196e..92cf600 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -97,10 +97,12 @@
 
         populateMaps();
         readConfigs();
+
         checkEnabledBarsHaveUniqueBarTypes();
         checkAllOverlappingBarsHaveDifferentZOrders();
         checkSystemBarEnabledForNotificationPanel();
         checkHideBottomBarForKeyboardConfigSync();
+
         setInsetPaddingsForOverlappingCorners();
         sortSystemBarSidesByZOrder();
     }
@@ -199,10 +201,10 @@
         BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");
         BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");
 
-        BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_GESTURES);
-        BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_GESTURES);
-        BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_GESTURES);
-        BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_GESTURES);
+        BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_MANDATORY_GESTURES);
+        BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES);
+        BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_MANDATORY_GESTURES);
+        BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_MANDATORY_GESTURES);
     }
 
     private void readConfigs() {
@@ -216,7 +218,7 @@
                     new SystemBarConfigBuilder()
                             .setSide(TOP)
                             .setGirth(mResources.getDimensionPixelSize(
-                                    com.android.internal.R.dimen.status_bar_height))
+                                    R.dimen.car_top_navigation_bar_height))
                             .setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
                             .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
                             .setHideForKeyboard(mResources.getBoolean(
@@ -230,7 +232,7 @@
                     new SystemBarConfigBuilder()
                             .setSide(BOTTOM)
                             .setGirth(mResources.getDimensionPixelSize(
-                                    com.android.internal.R.dimen.navigation_bar_height))
+                                    R.dimen.car_bottom_navigation_bar_height))
                             .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
                             .setZOrder(
                                     mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index c7155f4..b647f13 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.car.notification;
 
-import static android.view.WindowInsets.Type.navigationBars;
-
 import android.app.ActivityManager;
 import android.car.Car;
 import android.car.drivingstate.CarUxRestrictionsManager;
@@ -25,6 +23,8 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.GestureDetector;
@@ -82,6 +82,7 @@
     private final StatusBarStateController mStatusBarStateController;
     private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
     private final NotificationVisibilityLogger mNotificationVisibilityLogger;
+    private final int mNavBarHeight;
 
     private float mInitialBackgroundAlpha;
     private float mBackgroundAlphaDiff;
@@ -138,7 +139,10 @@
         mStatusBarStateController = statusBarStateController;
         mNotificationVisibilityLogger = notificationVisibilityLogger;
 
+        mNavBarHeight = mResources.getDimensionPixelSize(R.dimen.car_bottom_navigation_bar_height);
+
         mCommandQueue.addCallback(this);
+
         // Notification background setup.
         mInitialBackgroundAlpha = (float) mResources.getInteger(
                 R.integer.config_initialNotificationBackgroundAlpha) / 100;
@@ -179,6 +183,27 @@
         }
     }
 
+    @Override
+    public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
+        if (mContext.getDisplayId() != displayId) {
+            return;
+        }
+        boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
+        int bottomMargin = isKeyboardVisible ? 0 : mNavBarHeight;
+        ViewGroup container = (ViewGroup) getLayout();
+        if (container == null) {
+            // Notification panel hasn't been inflated before. We shouldn't try to update the layout
+            // params.
+            return;
+        }
+
+        ViewGroup.MarginLayoutParams params =
+                (ViewGroup.MarginLayoutParams) container.getLayoutParams();
+        params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
+        container.setLayoutParams(params);
+    }
+
     // OverlayViewController
 
     @Override
@@ -204,7 +229,7 @@
 
     @Override
     protected int getInsetTypesToFit() {
-        return navigationBars();
+        return 0;
     }
 
     @Override
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 4bc7bf6..462a6a9 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Switserse Duits"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgies"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaars"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaars, foneties"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiaans"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Deens"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noors"</string>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 7a4ffeff..1559fa8 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"የስዊዝ ጀርመን"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ቤልጂየም"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ቡልጋሪያ"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ቡልጋሪያኛ፣ ፎነቲክ"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ጣሊያንኛ"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ዴኒሽ"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ኖርዌጂያ"</string>
diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml
index a63821e..49fbef9 100644
--- a/packages/InputDevices/res/values-as/strings.xml
+++ b/packages/InputDevices/res/values-as/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ছুইছ জাৰ্মান"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"বেলজিয়ান"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"বুলগেৰিয়ান"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"বুলগেৰিয়ান ফ’নেটিক"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ইটালিয়ান"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ডেনিশ্ব"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ন\'ৰৱেয়ান"</string>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index 16badc4..c5a1e1e 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"İsveçrə Almanı"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belçikalı"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bolqar"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bolqar dili, Fonetika"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"İtalyan"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danimarkalı"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norveçli"</string>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
index 95ef459..16f1cb2 100644
--- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švajcarsko nemačka"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarska"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarska fonetska"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanska"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index 63b899a..6b0523f 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Нямецкая (Швейцарыя)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Бельгійская"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Балгарская"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Балгарская фанетычная"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Італьянская"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Дацкая"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Нарвежская"</string>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 90b7f6c..a7088c9 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"швейцарски немски"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"белгийски"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"български"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Българска фонетична клавиатура"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"италиански"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"датски"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвежки"</string>
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index f6a229c..b92ac8c 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarski njemački"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijski"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarski"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarski, fonetski"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanski"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"danski"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveški"</string>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index ec3b247..a5b5e10 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemany suís"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgar"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgar, fonètic"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italià"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danès"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruec"</string>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index dbe685c..cf2aecf 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Schweizertysk"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisk"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarsk"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarsk, fonetisk"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiensk"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dansk"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norsk"</string>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index fd7fca0..1e78685 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Schweizerdeutsch"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisch"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarisch"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarisch – phonetisch"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienisch"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dänisch"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norwegisch"</string>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 8bdd6f8..eb2cc9b 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Γερμανικά Ελβετίας"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Βελγικά"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Βουλγαρικά"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Βουλγαρικά (Φωνητικό)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Ιταλικά"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Δανικά"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Νορβηγικά"</string>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 5319f96..e8d6597 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán de Suiza"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro fonético"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danés"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruego"</string>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 95b3b1c..9396e46 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán suizo"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro (fonético)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danés"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruego"</string>
diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml
index a5fb8ac..cf28e9f 100644
--- a/packages/InputDevices/res/values-et/strings.xml
+++ b/packages/InputDevices/res/values-et/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Šveitsisaksa"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgia"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaaria"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaaria, foneetiline"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Itaalia"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Taani"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norra"</string>
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 1c75a7c..1e080fc 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemana (Suitza)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgikarra"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgariarra"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariarra, fonetikoa"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiarra"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Daniarra"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegiarra"</string>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index ca7d43a..5cb237e 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"آلمانی سوئیسی"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"بلژیکی"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"بلغاری"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"بلغاری، آوایی"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ایتالیایی"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"دانمارکی"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"نروژی"</string>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 2878c78..da72106 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"sveitsinsaksa"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgialainen"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulgaria"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bulgaria, foneettinen"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"italia"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"tanska"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norja"</string>
diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml
index e1ca7cf..40ede04 100644
--- a/packages/InputDevices/res/values-gl/strings.xml
+++ b/packages/InputDevices/res/values-gl/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán suízo"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarqués"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruegués"</string>
diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml
index bc2ee83..631fc14 100644
--- a/packages/InputDevices/res/values-gu/strings.xml
+++ b/packages/InputDevices/res/values-gu/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"સ્વિસ જર્મન"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"બેલ્જિયન"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"બલ્ગેરિયન"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"બલ્ગેરિયન ફોનેટિક"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ઇટાલિયન"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ડેનિશ"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"નોર્વેજીયન"</string>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 0430f86..aff2a37 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarsko-njemačka"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarska"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarska (fonetska)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"talijanska"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 76d10f5..50d667b4 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"svájci német"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bolgár"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bolgár fonetikus"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"olasz"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"dán"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norvég"</string>
diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml
index fa4e245..4a6fe2b 100644
--- a/packages/InputDevices/res/values-hy/strings.xml
+++ b/packages/InputDevices/res/values-hy/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Շվեյցարական գերմաներեն"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Բելգիական"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Բուլղարերեն"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"բուլղարերեն (հնչյունային)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Իտալերեն"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Դանիերեն"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Նորվեգերեն"</string>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index f5d173a..90ba97d 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Jerman Swiss"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgia"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaria"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaria, Fonetik"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italia"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Denmark"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norwegia"</string>
diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml
index 09eedd3..0889b21 100644
--- a/packages/InputDevices/res/values-is/strings.xml
+++ b/packages/InputDevices/res/values-is/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Svissneskt-þýskt"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgískt"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgarskt"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgarskt hljóðritunarlyklaborð"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Ítalskt"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norskt"</string>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index e15c01f..77f78c6 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tedesco svizzero"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgara, fonetica"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danese"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegese"</string>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 4abdf87..52641b2 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"גרמנית שוויצרית"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"בלגית"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"בולגרית"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"בולגרית פונטית"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"איטלקית"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"דנית"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"נורווגית"</string>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 606ab3c..2961548 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ドイツ語(スイス)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ベルギー語"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ブルガリア語"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ブルガリア語(表音)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"イタリア語"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"デンマーク語"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ノルウェー語"</string>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index b4b1a2d..2ccfeb2 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"შვეიცარიული გერმანული"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ბელგიური"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ბულგარული"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ბულგარული ფონეტიკური"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"იტალიური"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"დანიური"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ნორვეგიული"</string>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index 8f62eb3..1e3c693 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ಸ್ವಿಸ್ ಜರ್ಮನ್"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ಬೆಲ್ಜಿಯನ್"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ಬಲ್ಗೇರಿಯನ್‌"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ಬಲ್ಗೇರಿಯನ್ ಫೋನೆಟಿಕ್‌‌"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ಇಟಾಲಿಯನ್"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ಡ್ಯಾನಿಶ್"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ನಾರ್ವೇಜಿಯನ್"</string>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index b1f6582..1470504 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"독일어(스위스)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"벨기에어"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"불가리아어"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"불가리아어, 표음"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"이탈리아어"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"덴마크어"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"노르웨이어"</string>
diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml
index bc521a2..cb9dbb2 100644
--- a/packages/InputDevices/res/values-ky/strings.xml
+++ b/packages/InputDevices/res/values-ky/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Немис (Швейцария)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Белгия"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Болгар"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгарча, фонетикалык"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Италия"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Дания"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Норвег"</string>
diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml
index edb59f3..4ae4b7d 100644
--- a/packages/InputDevices/res/values-lo/strings.xml
+++ b/packages/InputDevices/res/values-lo/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ສະວິສ ເຢຍລະມັນ"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ເບວຢ້ຽນ"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ຮັງກາຣຽນ"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ບັງກາຣຽນ, ການອອກສຽງ"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ອິຕາລຽນ"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ເດັນນິຊ"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ນໍເວກຽນ"</string>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index f33eb42..d2aef7f 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Šveicarijos vokiečių k."</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgų k."</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarų k."</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Fonetinė bulgarų"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italų k."</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danų k."</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegų k."</string>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 4f47a3b..8f3ff0a 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Vācu (Šveice)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Beļģu"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgāru"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgāru, fonētiskā"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Itāļu"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dāņu"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvēģu"</string>
diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml
index 65fbf22..9e53443 100644
--- a/packages/InputDevices/res/values-ml/strings.xml
+++ b/packages/InputDevices/res/values-ml/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"സ്വിസ് ജര്‍മന്‍"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ബെൽജിയൻ"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ബൾഗേറിയൻ"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ബൾഗേറിയൻ, ഉച്ചാരണശബ്‌ദം"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ഇറ്റാലിയൻ"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ഡാനിഷ്"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"നോർവീജിയൻ"</string>
diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml
index a8fc661..18c2faf 100644
--- a/packages/InputDevices/res/values-mn/strings.xml
+++ b/packages/InputDevices/res/values-mn/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Швейцарийн Герман"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Бельги"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Болгар"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгар хэл, Авиа зүй"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Итали"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Дани"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Норвеги"</string>
diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml
index da6caab..d8788c9 100644
--- a/packages/InputDevices/res/values-mr/strings.xml
+++ b/packages/InputDevices/res/values-mr/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"स्विस जर्मन"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"बेल्जियन"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"बल्गेरियन"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"बल्गेरियन, फोनेटिक"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"इटालियन"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"डॅनिश"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"नॉर्वेजियन"</string>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index 975024b..8bc9b2a 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Jerman Switzerland"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Bahasa Belgium"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bahasa Bulgaria"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bahasa Bulgaria, Fonetik"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Bahasa Itali"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Bahasa Denmark"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Bahasa Norway"</string>
diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml
index 5484d9d..2672057 100644
--- a/packages/InputDevices/res/values-my/strings.xml
+++ b/packages/InputDevices/res/values-my/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ဆွစ် ဂျာမန်"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ဘယ်လ်ဂျီယန်"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ဘူဂေးရီယန်း"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ဘူလ်ဂေးရီးယား အသံထွက်"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"အီတာလီယန်"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ဒိန်းမတ်"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"နောဝေဂျီယန်"</string>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index 5484033..83b87e5 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Sveitsisk standardtysk"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisk"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarsk"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarsk, fonetisk"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiensk"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dansk"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norsk"</string>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index e000a30..6e58490 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Zwitsers Duits"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisch"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaars"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaars, fonetisch"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiaans"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Deens"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noors"</string>
diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml
index 6185ff7..aa16151 100644
--- a/packages/InputDevices/res/values-or/strings.xml
+++ b/packages/InputDevices/res/values-or/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ସୁଇସ୍ ଜର୍ମାନ୍‍"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ବେଲ୍‍ଜିଆନ୍‍"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ବୁଲଗାରିଆନ୍‍"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ବୁଲଗେରିଆନ୍, ଫୋନେଟିକ୍"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ଇଟାଲିୟାନ୍‌"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ଡାନିଶ୍‍"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ନରୱେଜିଆନ୍"</string>
diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml
index 97cf28b..7e5a03c 100644
--- a/packages/InputDevices/res/values-pa/strings.xml
+++ b/packages/InputDevices/res/values-pa/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ਸਵਿਸ ਜਰਮਨ"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"ਬੈਲਜੀਅਨ"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ਬਲਗੇਰੀਅਨ"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ਬਲਗੇਰੀਅਨ, ਧੁਨੀਆਤਮਿਕ"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ਇਤਾਲਵੀ"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ਡੈਨਿਸ਼"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ਨਾਰਵੇਜੀਅਨ"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 61819b6..51755e2 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Niemiecki (Szwajcaria)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgijski"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bułgarski"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bułgarski (znaki fonetyczne)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Włoski"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Duński"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norweski"</string>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index 665a1c7..1288688 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão suíço"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 1ccc644..89bb3e3 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão (Suíça)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 665a1c7..1288688 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão suíço"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index e0b4885..f7ff250 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Germană (Elveția)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiană"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgară"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgară fonetică"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiană"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Daneză"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegiană"</string>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 41ccf1a..0cb4f34 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"немецкий (Швейцария)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"нидерландский (Бельгия)"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"болгарский"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"болгарский (фонетическая)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"итальянский"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"датский"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвежский"</string>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 4d355d7..eb3c446 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ස්විස් ජර්මන්"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"බෙල්ගියන්"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"බල්ගේරියානු"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"බල්ගේරියානු, ශබ්දිම"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ඉතාලි"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ඩෙන්මාර්ක"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"නෝර්වීජියානු"</string>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index c7ff2fd..e7e15b0 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švajčiarske (nemčina)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgické"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulharské"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulharská fonetická klávesnica"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"talianske"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"dánske"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"nórske"</string>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 68741b4..f4d1e57 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarska nemška"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bolgarska"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bolgarščina (fonetična)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanska"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 2f68903..e3a2043 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"швајцарско немачка"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"белгијска"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"бугарска"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"бугарска фонетска"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"италијанска"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"данска"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвешка"</string>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index b465fa6..097ada4 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tyskt (Schweiz)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiskt"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgariskt"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariska (fonetiskt)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienskt"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norskt"</string>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 794d907..3257962 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Kijerumani cha Uswisi"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Kibelgiji"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Kibulgaria"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Kibulgaria, Fonetiki"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Kiitaliano"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Kidenmarki"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Kinorwei"</string>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index d40c3e0..c0253e5 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"స్విస్ జర్మన్"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"బెల్జియన్"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"బల్గేరియన్"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"బల్గేరియన్, ఫోనెటిక్"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"ఇటాలియన్"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"డేనిష్"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"నార్వేజియన్"</string>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 5913650..c8e0e62 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"เยอรมันสวิส"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"เบลเยียม"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"บัลแกเรีย"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ภาษาบัลแกเรีย ตามการออกเสียง"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"อิตาลี"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"เดนมาร์ก"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"นอร์เวย์"</string>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index a89cea5..f093abb 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"İsviçre Almancası"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belçika dili"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarca"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarca, Fonetik"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"İtalyanca"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danca"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norveççe"</string>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index 4b37ca9..d9b58d2 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"німецька (Швейцарія)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"бельгійська"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"болгарська"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгарська (фонетична)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"італійська"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"данська"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвезька"</string>
diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml
index ca42086..2bff7ed 100644
--- a/packages/InputDevices/res/values-ur/strings.xml
+++ b/packages/InputDevices/res/values-ur/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"سوئس جرمن"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"بیلجیئن"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"بلغاریائی"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"بلغاریائی، فونیٹک"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"اطالوی"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"ڈینش"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"نارویجین"</string>
diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml
index 77a06b5..9245aeb 100644
--- a/packages/InputDevices/res/values-uz/strings.xml
+++ b/packages/InputDevices/res/values-uz/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Nemis (Shveytsariya)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiyancha"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bolgarcha"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bolgar, fonetik"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italyancha"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Datcha"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegcha"</string>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index fd570ef..1b42ece 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tiếng Đức Thụy Sĩ"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Tiếng Bỉ"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Tiếng Bungary"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Tiếng Bulgaria, Ngữ âm"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Tiếng Ý"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Tiếng Đan Mạch"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Tiếng Na Uy"</string>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index afc373a..aa75605 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"瑞士德语"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利时语"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亚语"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亚语,注音"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"意大利语"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麦语"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威语"</string>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 775fa2a..dc824b9 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"德文(瑞士)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利時文"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亞文"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亞文 (拼音)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"意大利文"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麥文"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威文"</string>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index b4a059c..c2714da 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"德文 (瑞士)"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利時式"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亞文"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亞文 (拼音)"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"義大利文"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麥文"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威文"</string>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 0a2499a..3af1da1 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -19,8 +19,7 @@
     <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Isi-Swiss German"</string>
     <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Isi-Belgian"</string>
     <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Isi-Bulgarian"</string>
-    <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
-    <skip />
+    <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Isi-Bulgarian, Ifonetiki"</string>
     <string name="keyboard_layout_italian" msgid="6497079660449781213">"Isi-Italian"</string>
     <string name="keyboard_layout_danish" msgid="8036432066627127851">"Isi-Danish"</string>
     <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Isi-Norwegian"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 2696f5a..a279872 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -55,7 +55,7 @@
   </string-array>
   <string-array name="hdcp_checking_summaries">
     <item msgid="4045840870658484038">"Երբեք չօգտագործել HDCP ստուգումը"</item>
-    <item msgid="8254225038262324761">"Օգտագործել HDCP-ը` միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
+    <item msgid="8254225038262324761">"Օգտագործել HDCP-ը՝ միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
     <item msgid="6421717003037072581">"Միշտ օգտագործել HDCP ստուգումը"</item>
   </string-array>
   <string-array name="bt_hci_snoop_log_entries">
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index ffd95a4..e434cac 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -343,7 +343,7 @@
     <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"Թարմացվելիս ընդգծել սարքաշարի ծածկույթները կանաչ գույնով"</string>
     <string name="debug_hw_overdraw" msgid="8944851091008756796">"Վրիպազերծել GPU գերազանցումները"</string>
     <string name="disable_overlays" msgid="4206590799671557143">"Կասեցնել HW վրադրումները"</string>
-    <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն` էկրանի կազմման համար"</string>
+    <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն՝ էկրանի կազմման համար"</string>
     <string name="simulate_color_space" msgid="1206503300335835151">"Նմանակել գունատարածքը"</string>
     <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Ակտիվացնել OpenGL հետքերը"</string>
     <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Անջատել USB աուդիո երթուղումը"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
index f506b7c..0bde5c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -1,7 +1,9 @@
 # Default reviewers for this and subdirectories.
-qal@google.com
+andychou@google.com
 arcwang@google.com
-govenliu@google.com
 asapperstein@google.com
+goldmanj@google.com
+qal@google.com
+wengsu@google.com
 
-# Emergency approvers in case the above are not available
\ No newline at end of file
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index bcd2ff7..4db61b0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -175,6 +175,8 @@
         Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
         Settings.Secure.PANIC_GESTURE_ENABLED,
         Settings.Secure.PANIC_SOUND_ENABLED,
-        Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED
+        Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED,
+        Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+        Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 3630f25..1fde40c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -264,5 +264,8 @@
         VALIDATORS.put(Secure.PANIC_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.PANIC_SOUND_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ADAPTIVE_CONNECTIVITY_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(
+                Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS, NONE_NEGATIVE_LONG_VALIDATOR);
+        VALIDATORS.put(Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e7ec8b4..bc66601 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1875,6 +1875,15 @@
                 SecureSettingsProto.Assist.GESTURE_SETUP_COMPLETE);
         p.end(assistToken);
 
+        final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
+        dumpSetting(s, p,
+                Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+                SecureSettingsProto.AssistHandles.LEARNING_TIME_ELAPSED_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+                SecureSettingsProto.AssistHandles.LEARNING_EVENT_COUNT);
+        p.end(assistHandlesToken);
+
         final long autofillToken = p.start(SecureSettingsProto.AUTOFILL);
         dumpSetting(s, p,
                 Settings.Secure.AUTOFILL_SERVICE,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a1b9dcd..cf78a13 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -776,6 +776,7 @@
                   android:exported="true">
             <intent-filter>
                 <action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG" />
+                <action android:name="com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG" />
             </intent-filter>
         </receiver>
 
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 24b5c23..52b7fab 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -100,7 +100,7 @@
     <string name="kg_pin_accepted" msgid="1625501841604389716">"កូដត្រូវ​បានទទួល​យក!"</string>
     <string name="keyguard_carrier_default" msgid="6359808469637388586">"គ្មាន​សេវា​ទេ។"</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ប្ដូរ​វិធី​បញ្ចូល"</string>
-    <string name="airplane_mode" msgid="2528005343938497866">"មុខងារ​ពេល​ជិះ​យន្តហោះ"</string>
+    <string name="airplane_mode" msgid="2528005343938497866">"​ពេល​ជិះ​យន្តហោះ"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
     <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media.xml b/packages/SystemUI/res/drawable-television/ic_volume_media.xml
index e43c4b4..6a368d5 100644
--- a/packages/SystemUI/res/drawable-television/ic_volume_media.xml
+++ b/packages/SystemUI/res/drawable-television/ic_volume_media.xml
@@ -16,11 +16,11 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="@dimen/tv_volume_icons_size"
+    android:height="@dimen/tv_volume_icons_size"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
     <path
         android:fillColor="@color/tv_volume_dialog_accent"
-        android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/>
+        android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM10,8.83v6.34L7.83,13L5,13v-2h2.83L10,8.83zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77 0,-4.28 -2.99,-7.86 -7,-8.77z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml
index 0f6dc95..6eb944f 100644
--- a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml
+++ b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml
@@ -16,11 +16,13 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="@dimen/tv_volume_icons_size"
+    android:height="@dimen/tv_volume_icons_size"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/tv_volume_dialog_accent"
-        android:pathData="M3,15V9H7L12,4V20L7,15H3ZM14,7.97C15.48,8.71 16.5,10.23 16.5,12C16.5,13.77 15.48,15.29 14,16.02V7.97Z"/>
+    <group android:translateX="-2">
+        <path
+            android:fillColor="@color/tv_volume_dialog_accent"
+            android:pathData="M16,7.97v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02 0,-1.77 -1.02,-3.29 -2.5,-4.03zM5,9v6h4l5,5L14,4L9,9L5,9zM12,8.83v6.34L9.83,13L7,13v-2h2.83L12,8.83z"/>
+    </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml
index 4b59e13..b683089 100644
--- a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml
+++ b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml
@@ -16,12 +16,13 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="@dimen/tv_volume_icons_size"
+    android:height="@dimen/tv_volume_icons_size"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
-    <path
-        android:fillColor="@color/tv_volume_dialog_accent"
-        android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z"/>
+    <group android:translateX="-4">
+        <path
+            android:fillColor="@color/tv_volume_dialog_accent"
+            android:pathData="M14,8.83v6.34L11.83,13H9v-2h2.83L14,8.83M16,4l-5,5H7v6h4l5,5V4z"/>
+    </group>
 </vector>
-
diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml
new file mode 100644
index 0000000..7a44aa6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-television/ic_volume_media_off.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/tv_volume_icons_size"
+    android:height="@dimen/tv_volume_icons_size"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="@color/tv_volume_dialog_accent"
+        android:pathData="M4.34,2.93L2.93,4.34 7.29,8.7 7,9L3,9v6h4l5,5v-6.59l4.18,4.18c-0.65,0.49 -1.38,0.88 -2.18,1.11v2.06c1.34,-0.3 2.57,-0.92 3.61,-1.75l2.05,2.05 1.41,-1.41L4.34,2.93zM10,15.17L7.83,13L5,13v-2h2.83l0.88,-0.88L10,11.41v3.76zM19,12c0,0.82 -0.15,1.61 -0.41,2.34l1.53,1.53c0.56,-1.17 0.88,-2.48 0.88,-3.87 0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM12,4l-1.88,1.88L12,7.76zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v1.79l2.48,2.48c0.01,-0.08 0.02,-0.16 0.02,-0.24z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_off.xml b/packages/SystemUI/res/drawable/ic_volume_media_off.xml
new file mode 100644
index 0000000..875b7b6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_media_off.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_volume_media_mute" />
+</selector>
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
deleted file mode 100644
index 9b48a70..0000000
--- a/packages/SystemUI/res/drawable/tv_rect_dark_left_rounded.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-
-  <corners
-      android:bottomLeftRadius="8dp"
-      android:topLeftRadius="8dp" />
-  <solid android:color="@color/tv_audio_recording_indicator_background" />
-
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml b/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
deleted file mode 100644
index 0334875..0000000
--- a/packages/SystemUI/res/drawable/tv_rect_dark_right_rounded.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-
-  <corners
-      android:bottomRightRadius="8dp"
-      android:topRightRadius="8dp" />
-  <solid android:color="@color/tv_audio_recording_indicator_background" />
-
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_volume_row_seek_bar.xml b/packages/SystemUI/res/drawable/tv_volume_row_seek_bar.xml
new file mode 100644
index 0000000..fe76b63
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_volume_row_seek_bar.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/tv_volume_dialog_seek_bar_background" />
+            <corners android:radius="@dimen/tv_volume_seek_bar_width" />
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape android:shape="rectangle">
+                <solid android:color="@color/tv_volume_dialog_seek_bar_fill" />
+                <corners android:radius="@dimen/tv_volume_seek_bar_width" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml b/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml
new file mode 100644
index 0000000..588782d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_volume_row_seek_thumb.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
+    <solid android:color="@color/tv_volume_dialog_accent" />
+    <size android:width="@dimen/tv_volume_seek_bar_thumb_diameter"
+          android:height="@dimen/tv_volume_seek_bar_thumb_diameter" />
+    <stroke android:width="@dimen/tv_volume_seek_bar_thumb_focus_ring_width"
+            android:color="@color/tv_volume_dialog_seek_thumb_focus_ring"/>
+    <item name="android:shadowColor">@color/tv_volume_dialog_seek_thumb_shadow</item>
+    <item name="android:shadowRadius">@dimen/tv_volume_seek_bar_thumb_shadow_radius</item>
+    <item name="android:shadowDy">@dimen/tv_volume_seek_bar_thumb_shadow_dy</item>
+</shape>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index d28d566..4f6cb01 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -40,7 +40,7 @@
             android:fontFeatureSettings="tnum"
             android:background="@drawable/tv_volume_dialog_circle"
             android:textSize="@dimen/tv_volume_number_text_size"
-            android:textColor="@color/accent_tint_color_selector"/>
+            android:textColor="@color/tv_volume_dialog_accent"/>
         <TextView
             android:id="@+id/volume_row_header"
             android:layout_width="wrap_content"
@@ -61,6 +61,12 @@
                 android:layout_width="@dimen/volume_dialog_row_height"
                 android:layout_height="match_parent"
                 android:layout_gravity="center"
+                android:layoutDirection="ltr"
+                android:maxHeight="@dimen/tv_volume_seek_bar_width"
+                android:minHeight="@dimen/tv_volume_seek_bar_width"
+                android:thumb="@drawable/tv_volume_row_seek_thumb"
+                android:progressDrawable="@drawable/tv_volume_row_seek_bar"
+                android:splitTrack="false"
                 android:rotation="270" />
         </FrameLayout>
         <com.android.keyguard.AlphaOptimizedImageButton
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 0229e6e..73beefc 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -32,7 +32,7 @@
             android:id="@+id/header_icon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingEnd="16dp"/>
+            android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"/>
 
         <LinearLayout
             android:layout_width="match_parent"
@@ -70,36 +70,14 @@
         android:id="@+id/device_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="start|center_vertical"
         android:orientation="vertical">
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="12dp"/>
-
-        <include
-            layout="@layout/media_output_list_item"
-            android:id="@+id/group_item_controller"
-            android:visibility="gone"/>
-
-        <View
-            android:id="@+id/group_item_divider"
-            android:layout_width="match_parent"
-            android:layout_height="1dp"
-            android:background="?android:attr/listDivider"
-            android:visibility="gone"/>
-
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/list_result"
             android:scrollbars="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:overScrollMode="never"/>
-
-        <View
-            android:id="@+id/list_bottom_padding"
-            android:layout_width="match_parent"
-            android:layout_height="12dp"/>
     </LinearLayout>
 
     <View
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index fd89c0b..10ad829 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:clipChildren="false"
-        android:paddingTop="11dp"
+        android:paddingTop="@dimen/notification_guts_header_top_padding"
         android:clipToPadding="true">
         <ImageView
             android:id="@+id/conversation_icon"
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 92b3ff3..0a33d5e 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -30,10 +30,11 @@
     <LinearLayout
         android:id="@+id/header"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_guts_conversation_header_height"
+        android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:clipChildren="false"
-        android:clipToPadding="false">
+        android:paddingTop="@dimen/notification_guts_header_top_padding"
+        android:clipToPadding="true">
         <ImageView
             android:id="@+id/pkg_icon"
             android:layout_width="@dimen/notification_guts_conversation_icon_size"
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index c353d08..af66f8b 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -30,10 +30,11 @@
     <LinearLayout
         android:id="@+id/header"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_guts_conversation_header_height"
+        android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:clipChildren="false"
-        android:clipToPadding="false">
+        android:paddingTop="@dimen/notification_guts_header_top_padding"
+        android:clipToPadding="true">
         <ImageView
             android:id="@+id/icon"
             android:layout_width="@dimen/notification_guts_conversation_icon_size"
diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
index f9336a54..b62018d 100644
--- a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
+++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml
@@ -22,80 +22,17 @@
               android:padding="12dp">
 
     <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content">
+        android:layout_width="34dp"
+        android:layout_height="24dp"
+        android:layout_gravity="center"
+        android:background="@drawable/tv_rect_shadow_rounded">
 
-        <LinearLayout
-            android:id="@+id/icon_texts_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent">
-
-                <View
-                    android:id="@+id/icon_container_bg"
-                    android:layout_width="50dp"
-                    android:layout_height="match_parent"
-                    android:background="@drawable/tv_rect_dark_left_rounded"/>
-
-                <FrameLayout
-                    android:id="@+id/icon_mic"
-                    android:layout_width="34dp"
-                    android:layout_height="24dp"
-                    android:layout_gravity="center"
-                    android:background="@drawable/tv_rect_shadow_rounded">
-
-                    <ImageView
-                        android:layout_width="13dp"
-                        android:layout_height="13dp"
-                        android:layout_gravity="center"
-                        android:background="@drawable/tv_ic_mic_white"/>
-                </FrameLayout>
-
-            </FrameLayout>
-
-            <LinearLayout
-                android:id="@+id/texts_container"
-                android:layout_width="wrap_content"
-                android:layout_height="47dp"
-                android:background="@color/tv_audio_recording_indicator_background"
-                android:orientation="vertical"
-                android:visibility="visible">
-
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="14dp"
-                    android:layout_marginTop="10dp"
-                    android:layout_marginBottom="1dp"
-                    android:text="@string/mic_active"
-                    android:textColor="@android:color/white"
-                    android:fontFamily="sans-serif"
-                    android:textSize="10dp"/>
-
-                <TextView
-                    android:id="@+id/text"
-                    android:layout_width="wrap_content"
-                    android:layout_height="14dp"
-                    android:singleLine="true"
-                    android:text="SomeApplication accessed your microphone"
-                    android:textColor="@android:color/white"
-                    android:fontFamily="sans-serif"
-                    android:textSize="8dp"/>
-
-            </LinearLayout>
-
-        </LinearLayout>
+        <ImageView
+            android:layout_width="13dp"
+            android:layout_height="13dp"
+            android:layout_gravity="center"
+            android:src="@drawable/tv_ic_mic_white"/>
 
     </FrameLayout>
 
-    <View
-        android:id="@+id/bg_end"
-        android:layout_width="12dp"
-        android:layout_height="47dp"
-        android:background="@drawable/tv_rect_dark_right_rounded"
-        android:visibility="visible"/>
-
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index 6ced978..efd24c7 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -17,24 +17,26 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
-             android:layout_height="wrap_content">
-
+             android:layout_height="wrap_content"
+             android:screenReaderFocusable="true">
     <View
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_margin="@dimen/magnification_outer_border_margin"
+        android:importantForAccessibility="no"
         android:background="@android:color/black"/>
 
     <View
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_margin="@dimen/magnification_inner_border_margin"
+        android:importantForAccessibility="no"
         android:background="@color/magnification_border_color"/>
 
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:orientation="vertical">
+        android:importantForAccessibility="noHideDescendants">
 
         <View
             android:id="@+id/left_handle"
@@ -76,6 +78,7 @@
         android:layout_margin="@dimen/magnification_outer_border_margin"
         android:layout_gravity="right|bottom"
         android:scaleType="center"
+        android:importantForAccessibility="no"
         android:src="@drawable/ic_move_magnification"/>
 
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 556c390..72dfe74 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Wys laeprioriteit-kennisgewingikone"</string>
     <string name="other" msgid="429768510980739978">"Ander"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"verwyder teël"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"voeg teël aan einde by"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Skuif teël"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Voeg teël by"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Skuif na <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Voeg by posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kitsinstellingswysiger."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-kennisgewing: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Maak instellings oop."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c846297..0ec236d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"አነስተኛ ቅድሚያ ያላቸው የማሳወቂያ አዶዎችን አሳይ"</string>
     <string name="other" msgid="429768510980739978">"ሌላ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ሰቅ አስወግድ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ሰቅ መጨረሻው ላይ አክል"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ሰቁን ውሰድ"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ሰቅ ያክሉ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ውሰድ"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ቦታ አክል"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"የ<xliff:g id="POSITION">%1$d</xliff:g> አቀማመጥ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"የፈጣን ቅንብሮች አርታዒ።"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"የ<xliff:g id="ID_1">%1$s</xliff:g> ማሳወቂያ፦ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ቅንብሮችን ክፈት።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 785f8fe..e1d1950 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -899,20 +899,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"إظهار رموز الإشعارات ذات الأولوية المنخفضة"</string>
     <string name="other" msgid="429768510980739978">"غير ذلك"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"إزالة البطاقة"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"إضافة بطاقة إلى النهاية"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"نقل البطاقة"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"إضافة بطاقة"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"الانتقال إلى <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"الإضافة إلى الموضع <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"الموضع: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"برنامج تعديل الإعدادات السريعة."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"إشعار <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"فتح الإعدادات."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 059c4bc..61ba6dc 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"কম গুৰুত্বপূৰ্ণ জাননীৰ আইকনসমূহ দেখুৱাওক"</string>
     <string name="other" msgid="429768510980739978">"অন্যান্য"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল আঁতৰাবলৈ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"টাইল শেষত যোগ দিবলৈ"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল স্থানান্তৰ কৰক"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"টাইল যোগ দিয়ক"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰলৈ স্থানান্তৰ কৰক"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থানত যোগ দিয়ক"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থান"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিংসমূহৰ সম্পাদক।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> জাননী: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ছেটিংসমূহ খোলক।"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 2381d33..bee0e5f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Aşağı prioritet bildiriş işarələrini göstərin"</string>
     <string name="other" msgid="429768510980739978">"Digər"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"lövhəni silin"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"sona lövhə əlavə edin"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Lövhəni köçürün"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lövhə əlavə edin"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə köçürün"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə əlavə edin"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sürətli ayarlar redaktoru."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildiriş: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ayarları açın."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 55abfda..5966356 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obaveštenja niskog prioriteta"</string>
     <string name="other" msgid="429768510980739978">"Drugo"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklonili pločicu"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodali pločicu na kraj"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premestite pločicu"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajte pločicu"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premestite na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajte na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač za Brza podešavanja."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Obaveštenja za <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvori Podešavanja."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 47f9861..cedc375 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Паказваць значкі апавяшчэнняў з нізкім прыярытэтам"</string>
     <string name="other" msgid="429768510980739978">"Іншае"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"выдаліць плітку"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"дадаць плітку ў канец"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перамясціць плітку"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Дадаць плітку"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перамясціць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Дадаць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Пазіцыя <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Рэдактар хуткіх налад."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Апавяшчэнне <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Адкрыць налады."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index efe1267..1408840 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Показване на иконите за известията с нисък приоритет"</string>
     <string name="other" msgid="429768510980739978">"Друго"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"премахване на панел"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"добавяне на панел в края"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместване на панел"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавяне на панел"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместване към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор за бързи настройки."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Известие от <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отваряне на настройките."</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 811a971..41a2671 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obavještenja niskog prioriteta"</string>
     <string name="other" msgid="429768510980739978">"Ostalo"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodavanje kartice na kraj"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pomjeranje kartice"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pomjeranje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivanje brzih postavki"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> obavještenje: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvori postavke."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 793c44b..783f7877 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -92,10 +92,10 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vols iniciar la gravació?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Quan graves contingut, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou les contrasenyes, la informació de pagament, les fotos, els missatges i l\'àudio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Durant la gravació, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou contrasenyes, informació de pagament, fotos, missatges i àudio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grava l\'àudio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Àudio del dispositiu"</string>
-    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sons del dispositiu, com ara la música, les trucades i els sons de trucada"</string>
+    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"So del dispositiu, com ara música, trucades i sons de trucada"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"Micròfon"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Àudio del dispositiu i micròfon"</string>
     <string name="screenrecord_start" msgid="330991441575775004">"Inicia"</string>
@@ -387,7 +387,7 @@
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"La Wi‑Fi no està connectada"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTOMÀTICA"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix els colors"</string>
+    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix colors"</string>
     <string name="quick_settings_color_space_label" msgid="537528291083575559">"Mode de correcció de color"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Més opcions"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostra les icones de notificació amb prioritat baixa"</string>
     <string name="other" msgid="429768510980739978">"Altres"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"suprimir el mosaic"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"afegir una targeta al final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mou la targeta"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Afegeix una targeta"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mou a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuració ràpida."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificació de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Obre la configuració."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1d92389..f2e8a3f 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for notifikationer med lav prioritet"</string>
     <string name="other" msgid="429768510980739978">"Andet"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern kortet"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj kortet til slutningen"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt kortet"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj et kort"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flyt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åbn Indstillinger."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5976a1c..887aad5 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Symbole für Benachrichtigungen mit einer niedrigen Priorität anzeigen"</string>
     <string name="other" msgid="429768510980739978">"Sonstiges"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"die Kachel zu entfernen"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"die Kachel am Ende hinzuzufügen"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kachel verschieben"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Kachel hinzufügen"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Auf Position <xliff:g id="POSITION">%1$d</xliff:g> verschieben"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Zur Position <xliff:g id="POSITION">%1$d</xliff:g> hinzufügen"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor für Schnelleinstellungen."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Benachrichtigung von <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Einstellungen öffnen."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1eae5d4..1b912c7 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Εμφάνιση εικονιδίων ειδοποιήσεων χαμηλής προτεραιότητας"</string>
     <string name="other" msgid="429768510980739978">"Άλλο"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"κατάργηση πλακιδίου"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"προσθήκη πλακιδίου στο τέλος"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Μετακίνηση πλακιδίου"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Προσθήκη πλακιδίου"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Μετακίνηση στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Προσθήκη στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Ειδοποίηση <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Άνοιγμα ρυθμίσεων."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 4ea0341..065c17b 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3916e58..1cc6625 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 4ea0341..065c17b 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 4ea0341..065c17b 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b1ee41f..dfd42c3 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar íconos de notificaciones con prioridad baja"</string>
     <string name="other" msgid="429768510980739978">"Otros"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Quitar tarjeta"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"Agregar tarjeta al final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover la tarjeta"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Agregar tarjeta"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de Configuración rápida"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir Configuración"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 7e5361b..20b50ab 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconos de notificaciones con prioridad baja"</string>
     <string name="other" msgid="429768510980739978">"Otros"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar icono"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"añadir icono al final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover icono"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Añadir icono"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Añadir a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de ajustes rápidos."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir ajustes."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 78de793..ced0604 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Kuva madala prioriteediga märguande ikoonid"</string>
     <string name="other" msgid="429768510980739978">"Muu"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"paani eemaldamiseks"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"paani lõppu lisamiseks"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Teisalda paan"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisa paan"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Teisaldamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Asend <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kiirseadete redigeerija."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Teenuse <xliff:g id="ID_1">%1$s</xliff:g> märguanne: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ava seaded."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b5d8444..c1ab20c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Erakutsi lehentasun txikiko jakinarazpenen ikonoak"</string>
     <string name="other" msgid="429768510980739978">"Beste bat"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"kendu lauza"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"gehitu lauza amaieran"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Aldatu tokiz lauza"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Gehitu lauza"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Eraman <xliff:g id="POSITION">%1$d</xliff:g>garren kokapenera"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Gehitu <xliff:g id="POSITION">%1$d</xliff:g>garren kokapenean"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kokapena: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ezarpen bizkorren editorea."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> zerbitzuaren jakinarazpena: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ireki ezarpenak."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d453f91..f6cf179 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"نمایش نمادهای اعلان کم‌اهمیت"</string>
     <string name="other" msgid="429768510980739978">"موارد دیگر"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"برداشتن کاشی"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"افزودن کاشی به انتها"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"انتقال کاشی"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"افزودن کاشی"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"انتقال به <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ویرایشگر تنظیمات سریع."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"اعلان <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"باز کردن تنظیمات."</string>
@@ -967,7 +960,7 @@
     <string name="slice_permission_text_2" msgid="6758906940360746983">"- می‌تواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
     <string name="slice_permission_checkbox" msgid="4242888137592298523">"به <xliff:g id="APP">%1$s</xliff:g> اجازه داده شود تکه‌هایی از برنامه‌ها نشان دهد"</string>
     <string name="slice_permission_allow" msgid="6340449521277951123">"مجاز"</string>
-    <string name="slice_permission_deny" msgid="6870256451658176895">"رد کردن"</string>
+    <string name="slice_permission_deny" msgid="6870256451658176895">"مجاز نبودن"</string>
     <string name="auto_saver_title" msgid="6873691178754086596">"برای زمان‌بندی «بهینه‌سازی باتری» ضربه بزنید"</string>
     <string name="auto_saver_text" msgid="3214960308353838764">"وقتی باتری روبه‌اتمام است، بهینه‌سازی باتری را روشن کنید"</string>
     <string name="no_auto_saver_action" msgid="7467924389609773835">"نه متشکرم"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dde2449..3d9a6db 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -379,7 +379,7 @@
     <string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wi-Fi on käytössä"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ei Wi-Fi-verkkoja käytettävissä"</string>
     <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Otetaan käyttöön…"</string>
-    <string name="quick_settings_cast_title" msgid="2279220930629235211">"Näytön suoratoisto"</string>
+    <string name="quick_settings_cast_title" msgid="2279220930629235211">"Näytön striimaus"</string>
     <string name="quick_settings_casting" msgid="1435880708719268055">"Lähetetään"</string>
     <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nimetön laite"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2580520859212250265">"Valmis lähetystä varten"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Näytä vähemmän tärkeät ilmoituskuvakkeet"</string>
     <string name="other" msgid="429768510980739978">"Muu"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"poista kiekko"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"lisää kiekko loppuun"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Siirrä kiekkoa"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisää kiekko"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Siirrä paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisää paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Pika-asetusten muokkausnäkymä"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Ilmoitus kohteesta <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Avaa asetukset."</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index aba2d8f..9075a69 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconas das notificacións que teñan baixa prioridade"</string>
     <string name="other" msgid="429768510980739978">"Outros"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar tarxeta"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"engadir tarxeta ao final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover tarxeta"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Engadir tarxeta"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engadir á posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuración rápida."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configuración."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 1acef35..e8b4460 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"ઓછી પ્રાધાન્યતાનું નોટિફિકેશન આઇકન બતાવો"</string>
     <string name="other" msgid="429768510980739978">"અન્ય"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ટાઇલ કાઢી નાખો"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ટાઇલને અંતે ઉમેરો"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ટાઇલ ખસેડો"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ટાઇલ ઉમેરો"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> પર ખસેડો"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"જગ્યા પર <xliff:g id="POSITION">%1$d</xliff:g> ઉમેરો"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ્સ સંપાદક."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> નોટિફિકેશન: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ્સ ખોલો."</string>
diff --git a/packages/SystemUI/res/values-h740dp-port/dimens.xml b/packages/SystemUI/res/values-h740dp-port/dimens.xml
new file mode 100644
index 0000000..966066f
--- /dev/null
+++ b/packages/SystemUI/res/values-h740dp-port/dimens.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <dimen name="qs_tile_height">106dp</dimen>
+    <dimen name="qs_tile_margin_vertical">24dp</dimen>
+
+    <!-- The height of the qs customize header. Should be
+         (qs_panel_padding_top (48dp) +  brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
+         (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
+    -->
+    <dimen name="qs_customize_header_min_height">46dp</dimen>
+    <dimen name="qs_tile_margin_top">18dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9b3f997..649299b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obavijesti niskog prioriteta"</string>
     <string name="other" msgid="429768510980739978">"Ostalo"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodavanje kartice na kraj"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premještanje kartice"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premještanje u prostoriju <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač brzih postavki."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> obavijest: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvaranje postavki."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7f4fa9d..f658bb7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Alacsony prioritású értesítési ikonok mutatása"</string>
     <string name="other" msgid="429768510980739978">"Egyéb"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"mozaik eltávolításához"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"mozaiknak a végéhez való hozzáadásához"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mozaik áthelyezése"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Mozaik hozzáadása"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Áthelyezés ide: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Gyorsbeállítások szerkesztője"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-értesítések: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Beállítások megnyitása."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 70cbf49..28c79fb 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Ցուցադրել ցածր առաջնահերթության ծանուցումների պատկերակները"</string>
     <string name="other" msgid="429768510980739978">"Այլ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"հեռացնել սալիկը"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ավելացնել սալիկ վերջում"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Տեղափոխել սալիկը"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ավելացնել սալիկ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Տեղափոխել դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Արագ կարգավորումների խմբագրիչ:"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ծանուցում՝ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Բացել կարգավորումները:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dc0a512..12f42e8 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -862,7 +862,7 @@
     <string name="left_icon" msgid="5036278531966897006">"Ikon kiri"</string>
     <string name="right_icon" msgid="1103955040645237425">"Ikon kanan"</string>
     <string name="drag_to_add_tiles" msgid="8933270127508303672">"Tahan dan tarik untuk menambahkan kartu"</string>
-    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan tarik untuk mengatur ulang kartu"</string>
+    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan tarik untuk menata ulang kartu"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Tarik ke sini untuk menghapus"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Anda membutuhkan setidaknya <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kartu"</string>
     <string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Tampilkan ikon notifikasi prioritas rendah"</string>
     <string name="other" msgid="429768510980739978">"Lainnya"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"menghapus kartu"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"menambahkan kartu ke akhir"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pindahkan kartu"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan kartu"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pindahkan ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan ke posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor setelan cepat."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notifikasi <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buka setelan."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index f79796b..1f8f2aa 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -861,10 +861,10 @@
     <string name="right_keycode" msgid="2480715509844798438">"Lykiltákn til hægri"</string>
     <string name="left_icon" msgid="5036278531966897006">"Tákn til vinstri"</string>
     <string name="right_icon" msgid="1103955040645237425">"Tákn til hægri"</string>
-    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Haltu inni og dragðu til að bæta við reitum"</string>
+    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Haltu inni og dragðu til að bæta við flísum"</string>
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Haltu og dragðu til að endurraða flísum"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Dragðu hingað til að fjarlægja"</string>
-    <string name="drag_to_remove_disabled" msgid="933046987838658850">"Reitirnir mega ekki vera færri en <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
+    <string name="drag_to_remove_disabled" msgid="933046987838658850">"Flísarnar mega ekki vera færri en <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
     <string name="qs_edit" msgid="5583565172803472437">"Breyta"</string>
     <string name="tuner_time" msgid="2450785840990529997">"Tími"</string>
   <string-array name="clock_options">
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Sýna tákn fyrir tilkynningar með litlum forgangi"</string>
     <string name="other" msgid="429768510980739978">"Annað"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjarlægja reit"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"bæta reit við aftast"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Færa reit"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Bæta reit við"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Færa í <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bæta við í stöðu <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Staða <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Flýtistillingaritill."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> tilkynning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Opna stillingar."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3b99dc2..eb76a4b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostra icone di notifiche con priorità bassa"</string>
     <string name="other" msgid="429768510980739978">"Altro"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"rimuovere il riquadro"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"aggiungere il riquadro alla fine"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Sposta riquadro"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Aggiungi riquadro"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Sposta nella posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor di impostazioni rapide."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notifica di <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Apri le impostazioni."</string>
@@ -975,7 +968,7 @@
     <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Il Risparmio energetico verrà attivato automaticamente quando la carica della batteria sarà inferiore a <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"Impostazioni"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
-    <string name="heap_dump_tile_name" msgid="2464189856478823046">"Esegui dump heap SysUI"</string>
+    <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"L\'app <xliff:g id="APP">%1$s</xliff:g> sta usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3bb8ea5..31e6bef 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"הצגת סמלי התראות בעדיפות נמוכה"</string>
     <string name="other" msgid="429768510980739978">"אחר"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"הסרת האריח"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"הוספת האריח לקצה"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"הזזת האריח"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"הוספת אריח"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"העברה אל <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"הוספה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"עורך הגדרות מהירות."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"התראות <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"פתיחת הגדרות."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2c55569..b358f3d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"優先度の低い通知アイコンを表示"</string>
     <string name="other" msgid="429768510980739978">"その他"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"タイルを削除"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"タイルを最後に追加"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"タイルを移動"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"タイルを追加"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> に移動"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に追加"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"クイック設定エディタ"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> の通知: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"設定を開きます。"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index ca5b7da..4e85d60 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"დაბალი პრიორიტეტის მქონე შეტყობინებების ხატულების ჩვენება"</string>
     <string name="other" msgid="429768510980739978">"სხვა"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"მოზაიკის ფილის წაშლა"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ფილის ბოლოში დამატება"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"მოზაიკის გადატანა"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"მოზაიკის დამატება"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"გადატანა <xliff:g id="POSITION">%1$d</xliff:g>-ზე"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"სწრაფი პარამეტრების რედაქტორი."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> შეტყობინება: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"პარამეტრების გახსნა."</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a4bf498..f172106 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -865,7 +865,7 @@
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердің ретін өзгерту үшін оларды басып тұрып сүйреңіз"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Керексіздерін осы жерге сүйреңіз"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Кемінде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> бөлшек қажет."</string>
-    <string name="qs_edit" msgid="5583565172803472437">"Өңдеу"</string>
+    <string name="qs_edit" msgid="5583565172803472437">"Өзгерту"</string>
     <string name="tuner_time" msgid="2450785840990529997">"Уақыт"</string>
   <string-array name="clock_options">
     <item msgid="3986445361435142273">"Сағаттарды, минуттарды және секундтарды көрсету"</item>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Маңызды емес хабарландыру белгішелерін көрсету"</string>
     <string name="other" msgid="429768510980739978">"Басқа"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"бөлшекті өшіру"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"бөлшекті соңына қосу"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Бөлшекті жылжыту"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Бөлшек қосу"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> орнына жылжыту"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> орнына қосу"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> орны"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Жылдам параметрлер өңдегіші."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> хабарландыруы: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Параметрлерді ашу."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7eaa303..b126a11 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"បង្ហាញ​រូប​ការជូនដំណឹង​ដែលមានអាទិភាពទាប"</string>
     <string name="other" msgid="429768510980739978">"ផ្សេងៗ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ដកប្រអប់ចេញ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"បញ្ចូល​ប្រអប់ទៅ​ខាងចុង"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ផ្លាស់ទី​ប្រអប់"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"បញ្ចូល​ប្រអប់"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ផ្លាស់​ទីទៅ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"បញ្ចូលទៅ​ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"កម្មវិធីកែការកំណត់រហ័ស"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ការជូនដំណឹង៖ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"បើកការកំណត់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 79f8452..475677b 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -387,7 +387,7 @@
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"ಸ್ವಯಂ"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
+    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣಗಳನ್ನು ಇನ್ವರ್ಟ್ ಮಾಡಿ"</string>
     <string name="quick_settings_color_space_label" msgid="537528291083575559">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ ಮೋಡ್"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"ಕಡಿಮೆ-ಆದ್ಯತೆ ಸೂಚನೆಯ ಐಕಾನ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="other" msgid="429768510980739978">"ಇತರ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ಟೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ಕೊನೆಯಲ್ಲಿ ಟೈಲ್ ಸೇರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ಟೈಲ್ ಸರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ಟೈಲ್ ಸೇರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ಇಲ್ಲಿಗೆ ಸರಿಸಿ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಎಡಿಟರ್."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ಅಧಿಸೂಚನೆ: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6a755e5..ac7f04e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -371,7 +371,7 @@
     <string name="quick_settings_time_label" msgid="3352680970557509303">"시간"</string>
     <string name="quick_settings_user_label" msgid="1253515509432672496">"나"</string>
     <string name="quick_settings_user_title" msgid="8673045967216204537">"사용자"</string>
-    <string name="quick_settings_user_new_user" msgid="3347905871336069666">"새 사용자"</string>
+    <string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string>
     <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"연결되어 있지 않음"</string>
     <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"네트워크가 연결되지 않음"</string>
@@ -473,7 +473,7 @@
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"현재 사용자: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"프로필 표시"</string>
     <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string>
-    <string name="user_new_user_name" msgid="2019166282704195789">"새 사용자"</string>
+    <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string>
     <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"우선순위가 낮은 알림 아이콘 표시"</string>
     <string name="other" msgid="429768510980739978">"기타"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"타일 삭제"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"끝에 타일 추가"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"타일 이동"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"타일 추가"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> 위치로 이동"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> 위치에 추가"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> 위치"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"빠른 설정 편집기"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 알림: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"설정 열기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index a740d07..d775823 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -862,7 +862,7 @@
     <string name="left_icon" msgid="5036278531966897006">"¨Солго¨ сүрөтчөсү"</string>
     <string name="right_icon" msgid="1103955040645237425">"¨Оңго¨ сүрөтчөсү"</string>
     <string name="drag_to_add_tiles" msgid="8933270127508303672">"Керектүү элементтерди сүйрөп келиңиз"</string>
-    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн, кармап туруп, сүйрөңүз"</string>
+    <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Сизге жок дегенде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> мозаика керек"</string>
     <string name="qs_edit" msgid="5583565172803472437">"Түзөтүү"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Анча маанилүү эмес билдирменин сүрөтчөлөрүн көрсөтүү"</string>
     <string name="other" msgid="429768510980739978">"Башка"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"плитканы өчүрүү"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"плитканы аягына кошуу"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Плитканы жылдыруу"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Плитка кошуу"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Төмөнкүгө жылдыруу: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ыкчам жөндөөлөр түзөткүчү."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> эскертмеси: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Жөндөөлөрдү ачуу."</string>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 8237919..95ff59b 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -16,10 +16,17 @@
 
 <resources>
   <!-- Height of volume bar -->
-  <dimen name="volume_dialog_row_height">200dp</dimen>
-  <dimen name="volume_dialog_panel_transparent_padding">17dp</dimen>
+  <dimen name="volume_dialog_row_height">190dp</dimen>
+  <dimen name="volume_dialog_row_width">48dp</dimen>
+  <dimen name="volume_dialog_panel_transparent_padding">24dp</dimen>
   <dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
-  <dimen name="tv_volume_dialog_corner_radius">40dp</dimen>
-  <dimen name="tv_volume_dialog_row_padding">5dp</dimen>
-  <dimen name="tv_volume_number_text_size">16dp</dimen>
+  <dimen name="tv_volume_dialog_corner_radius">36dp</dimen>
+  <dimen name="tv_volume_dialog_row_padding">6dp</dimen>
+  <dimen name="tv_volume_number_text_size">16sp</dimen>
+  <dimen name="tv_volume_seek_bar_width">4dp</dimen>
+  <dimen name="tv_volume_seek_bar_thumb_diameter">24dp</dimen>
+  <dimen name="tv_volume_seek_bar_thumb_focus_ring_width">8dp</dimen>
+  <dimen name="tv_volume_icons_size">20dp</dimen>
+  <dimen name="tv_volume_seek_bar_thumb_shadow_radius">4.0</dimen>
+  <dimen name="tv_volume_seek_bar_thumb_shadow_dy">4.0</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1fb2ca0..67642d3 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"ສະແດງໄອຄອນການແຈ້ງເຕືອນຄວາມສຳຄັນຕ່ຳ"</string>
     <string name="other" msgid="429768510980739978">"ອື່ນໆ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ລຶບແຜ່ນອອກ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ເພີ່ມແຜ່ນໃສ່ທ້າຍ"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ຍ້າຍແຜ່ນ"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ເພີ່ມແຜ່ນ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ຍ້າຍໄປ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"ການແຈ້ງເຕືອນ <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ເປີດການຕັ້ງຄ່າ."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index bd24722..e17f6e4 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Rodyti mažo prioriteto pranešimų piktogramas"</string>
     <string name="other" msgid="429768510980739978">"Kita"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"pašalintumėte išklotinės elementą"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pridėtumėte išklotinės elementą gale"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Perkelti išklotinės elementą"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridėti išklotinės elementą"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Perkelkite į <xliff:g id="POSITION">%1$d</xliff:g> poziciją"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sparčiųjų nustatymų redagavimo priemonė."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"„<xliff:g id="ID_1">%1$s</xliff:g>“ pranešimas: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Atidaryti nustatymus."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e8d9a4d..96d563c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Rādīt zemas prioritātes paziņojumu ikonas"</string>
     <string name="other" msgid="429768510980739978">"Citi"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"noņemt elementu"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pievienot elementu beigās"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pārvietot elementu"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pievienot elementu"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pārvietot uz pozīciju numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pievienot elementu pozīcijā numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozīcija numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ātro iestatījumu redaktors."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> paziņojums: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Atvērt iestatījumus."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 164cb96..f53147e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Прикажувај икони за известувања со низок приоритет"</string>
     <string name="other" msgid="429768510980739978">"Друго"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"отстранување на плочката"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додавање на плочката на крај"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместување на плочката"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додавање плочка"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместување на <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додавање на позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уредник за брзи поставки."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Известување од <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отворете ги поставките."</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index ba379d3..fc68681 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -387,7 +387,7 @@
     <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"വൈഫൈ കണക്റ്റ് ചെയ്‌തിട്ടില്ല"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"യാന്ത്രികം"</string>
-    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നിറം മാറ്റുക"</string>
+    <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നെഗറ്റീവ് ലുക്ക്"</string>
     <string name="quick_settings_color_space_label" msgid="537528291083575559">"വർണ്ണം ശരിയാക്കൽ മോഡ്"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
     <string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"പ്രാധാന്യം കുറഞ്ഞ അറിയിപ്പ് ചിഹ്‌നങ്ങൾ"</string>
     <string name="other" msgid="429768510980739978">"മറ്റുള്ളവ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ടൈൽ നീക്കം ചെയ്യുക"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ടൈൽ, അവസാന ഭാഗത്ത് ചേർക്കുക"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ടൈൽ നീക്കുക"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ടൈൽ ചേർക്കുക"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>-ലേക്ക് നീക്കുക"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>-ൽ ചേർക്കുക"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> അറിയിപ്പ്: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ക്രമീകരണം തുറക്കുക."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 56c5ef2..1c82e48 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Бага ач холбогдолтой мэдэгдлийн дүрс тэмдгийг харуулах"</string>
     <string name="other" msgid="429768510980739978">"Бусад"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"хавтанг хасна уу"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"дуусгахын тулд хавтан нэмэх"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Хавтанг зөөх"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Хавтан нэмэх"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> руу зөөнө үү"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> байрлалд нэмнэ үү"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Түргэн тохиргоо засварлагч."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> мэдэгдэл: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Тохиргоог нээнэ үү."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 728065f..b26f89f 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"कमी प्राधान्य सूचना आयकन दर्शवा"</string>
     <string name="other" msgid="429768510980739978">"अन्य"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल काढून टाका"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"टाइल शेवटच्या स्थानावर जोडा"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल हलवा"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल जोडा"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> यावर हलवा"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> स्थानावर जोडा"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थान <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिंग्ज संपादक."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> सूचना: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"सेटिंग्ज उघडा."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 62d845c..92bc807 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Tunjukkan ikon pemberitahuan keutamaan rendah"</string>
     <string name="other" msgid="429768510980739978">"Lain-lain"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alih keluar jubin"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"tambahkan jubin pada bahagian hujung"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Alihkan jubin"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan jubin"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Alih ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan pada kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor tetapan pantas."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Pemberitahuan <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buka tetapan."</string>
@@ -975,7 +968,7 @@
     <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Penjimat Bateri akan dihidupkan secara automatik setelah kuasa bateri kurang daripada <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"Tetapan"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
-    <string name="heap_dump_tile_name" msgid="2464189856478823046">"Longgok Tmbunn SysUI"</string>
+    <string name="heap_dump_tile_name" msgid="2464189856478823046">"DumpSys"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> sedang menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g> anda."</string>
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e72f169..9cc9398 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"အရေးမကြီးသော အကြောင်းကြားချက် သင်္ကေတများ ပြရန်"</string>
     <string name="other" msgid="429768510980739978">"အခြား"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"အကွက်ငယ်ကို ဖယ်ရှားရန်"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"အဆုံးတွင် အကွက်ငယ်ထည့်ရန်"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"အကွက်ငယ်ကို ရွှေ့ရန်"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"အကွက်ငယ်ကို ထည့်ရန်"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> သို့ ရွှေ့ရန်"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထားသို့ ပေါင်းထည့်ရန်"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထား"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> အကြောင်းကြားချက် − <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ဆက်တင်များကို ဖွင့်ပါ။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 41aabcb..92ae689 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for varsler med lav prioritet"</string>
     <string name="other" msgid="429768510980739978">"Annet"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjerne infobrikken"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"legge til en infobrikke på slutten"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytt infobrikken"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Legg til en infobrikke"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Legg til posisjonen <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisjon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsvindu for hurtiginnstillinger."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-varsel: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åpne innstillingene."</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0cf09d2..1346874 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकताका सूचना आइकनहरू देखाउनुहोस्"</string>
     <string name="other" msgid="429768510980739978">"अन्य"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाउनुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"टाइल अन्त्यमा हाल्नुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल सार्नुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल हाल्नुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"टाइल सारेर <xliff:g id="POSITION">%1$d</xliff:g> मा लैजानुहोस्"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल यो अवस्था <xliff:g id="POSITION">%1$d</xliff:g> मा हाल्नुहोस्"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिङ सम्पादक।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> को सूचना: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"सेटिङहरूलाई खोल्नुहोस्।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 49e097e..139b57b 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Pictogrammen voor meldingen met lage prioriteit weergeven"</string>
     <string name="other" msgid="429768510980739978">"Overig"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"tegel verwijderen"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"tegel toevoegen aan einde"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Tegel verplaatsen"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tegel toevoegen"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Verplaatsen naar <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Toevoegen aan positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor voor \'Snelle instellingen\'."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-melding: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Instellingen openen."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index c3105ff..3973734 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -861,7 +861,7 @@
     <string name="right_keycode" msgid="2480715509844798438">"ଡାହାଣ କୀ\'କୋଡ୍‍"</string>
     <string name="left_icon" msgid="5036278531966897006">"ବାମ ଆଇକନ୍‍"</string>
     <string name="right_icon" msgid="1103955040645237425">"ଡାହାଣ ଆଇକନ୍"</string>
-    <string name="drag_to_add_tiles" msgid="8933270127508303672">"ଟାଇଲ୍ ଯୋଡ଼ିବା ପାଇଁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
+    <string name="drag_to_add_tiles" msgid="8933270127508303672">"ଟାଇଲ୍ ଯୋଗ କରିବା ପାଇଁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ଟାଇଲ୍‍ ପୁଣି ସଜାଇବାକୁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"ବାହାର କରିବାକୁ ଏଠାକୁ ଡ୍ରାଗ୍‍ କରନ୍ତୁ"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"ଆପଣଙ୍କର ଅତିକମ୍‌ରେ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>ଟି ଟାଇଲ୍ ଆବଶ୍ୟକ"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"କମ୍‍-ଅଗ୍ରାଧିକାର ବିଜ୍ଞପ୍ତି ଆଇକନ୍‍ ଦେଖାନ୍ତୁ"</string>
     <string name="other" msgid="429768510980739978">"ଅନ୍ୟାନ୍ୟ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ଟାଇଲ୍ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ଶେଷରେ ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ଟାଇଲ୍ ମୁଭ୍ କରନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>କୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ଅବସ୍ଥିତିରେ ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ସେଟିଂସ୍ ଖୋଲନ୍ତୁ।"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index b12dfb3..e727f48a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"ਘੱਟ ਤਰਜੀਹ ਵਾਲੇ ਸੂਚਨਾ ਪ੍ਰਤੀਕਾਂ ਨੂੰ ਦਿਖਾਓ"</string>
     <string name="other" msgid="429768510980739978">"ਹੋਰ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ਟਾਇਲ ਹਟਾਓ"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ਟਾਇਲ ਨੂੰ ਅੰਤ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ਟਾਇਲ ਨੂੰ ਲਿਜਾਓ"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> \'ਤੇ ਲਿਜਾਓ"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ਸਥਾਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ਸਥਾਨ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ਸੂਚਨਾ: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d195977..f188aaa 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Pokazuj ikony powiadomień o niskim priorytecie"</string>
     <string name="other" msgid="429768510980739978">"Inne"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"usunąć kartę"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodać kartę na końcu"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Przenieś kartę"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodaj kartę"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Przenieś do pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodaj w pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozycja <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Edytor szybkich ustawień."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Powiadomienie z aplikacji <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otwórz ustawienia."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 6f96f37..8c8adae 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
     <string name="other" msgid="429768510980739978">"Outros"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o bloco ao final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configurações."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 93999f6..082e14e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -861,7 +861,7 @@
     <string name="right_keycode" msgid="2480715509844798438">"Código de tecla direito"</string>
     <string name="left_icon" msgid="5036278531966897006">"Ícone esquerdo"</string>
     <string name="right_icon" msgid="1103955040645237425">"Ícone direito"</string>
-    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Toque sem soltar e arraste para adicionar mosaicos."</string>
+    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Tocar sem soltar e arrastar para adicionar mosaicos"</string>
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tocar sem soltar e arrastar para reorganizar os mosaicos"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastar para aqui para remover"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Necessita de, pelo menos, <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> cartões"</string>
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de prioridade baixa"</string>
     <string name="other" msgid="429768510980739978">"Outro"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o cartão"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o cartão ao final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover cartão"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar cartão"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mova para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir as definições."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6f96f37..8c8adae 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
     <string name="other" msgid="429768510980739978">"Outros"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o bloco ao final"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configurações."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 9810cc5..4128c21 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afișați pictogramele de notificare cu prioritate redusă"</string>
     <string name="other" msgid="429768510980739978">"Altele"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"eliminați cardul"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adăugați cardul la sfârșit"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mutați cardul"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adăugați un card"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mutați pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adăugați pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editorul pentru setări rapide."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificare <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Deschideți setările."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9f43b5a..66e3ec3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Показывать значки уведомлений с низким приоритетом"</string>
     <string name="other" msgid="429768510980739978">"Другое"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"удалить кнопку быстрого доступа"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"добавить кнопку быстрого доступа в конец"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Переместить кнопку быстрого доступа"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавить кнопку быстрого доступа"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Переместить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор быстрых настроек."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Уведомление <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Открыть настройки."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 700f510..98e8d1f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"අඩු ප්‍රමුඛතා දැනුම්දීම් අයිකන පෙන්වන්න"</string>
     <string name="other" msgid="429768510980739978">"වෙනත්"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ටයිල් ඉවත් කරන්න"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"අගට ටයිල් එක් කරන්න"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ටයිල් ගෙන යන්න"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ටයිල් එක් කරන්න"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> වෙත ගෙන යන්න"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ස්ථානයට එක් කරන්න"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> දැනුම්දීම: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"සැකසීම් විවෘත කරන්න."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 62df35a..d9c6279 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Zobraziť ikony upozornení s nízkou prioritou"</string>
     <string name="other" msgid="429768510980739978">"Ďalšie"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstrániť kartu"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pridať kartu na koniec"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Presunúť kartu"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridať kartu"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Presunúť na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rýchlych nastavení"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Upozornenie <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvoriť nastavenia"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 25bdd65..778938c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Pokaži ikone obvestil z nizko stopnjo prednosti"</string>
     <string name="other" msgid="429768510980739978">"Drugo"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranitev ploščice"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodajanje ploščice na konec"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premik ploščice"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajanje ploščice"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premik na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Urejevalnik hitrih nastavitev."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Obvestilo za <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Odpri nastavitve."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e117602..90f1c5a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -884,20 +884,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Прикажи иконе обавештења ниског приоритета"</string>
     <string name="other" msgid="429768510980739978">"Друго"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"уклонили плочицу"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додали плочицу на крај"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместите плочицу"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додајте плочицу"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместите на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додајте на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уређивач за Брза подешавања."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Обавештења за <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отвори Подешавања."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8559b0b..8918f51 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Visa ikoner för aviseringar med låg prioritet"</string>
     <string name="other" msgid="429768510980739978">"Annat"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ta bort ruta"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"lägg till ruta i slutet"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytta ruta"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lägg till ruta"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytta till <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigerare för snabbinställningar."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-avisering: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Öppna inställningarna."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 76b86ee..3949f2d 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Onyesha aikoni za arifa zisizo muhimu"</string>
     <string name="other" msgid="429768510980739978">"Nyingine"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ondoa kigae"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ongeza kigae mwishoni"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hamisha kigae"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ongeza kigae"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Hamishia kwenye <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ongeza kwenye nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kihariri cha Mipangilio ya haraka."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Arifa kutoka <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Fungua mipangilio."</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 925c958..d7a27b8 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"తక్కువ ప్రాధాన్యత నోటిఫికేషన్ చిహ్నాలను చూపించు"</string>
     <string name="other" msgid="429768510980739978">"ఇతరం"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"టైల్‌ను తీసివేయండి"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ముగించడానికి టైల్‌ను జోడించండి"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"టైల్‌ను తరలించండి"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"టైల్‌ను జోడించండి"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>కు తరలించండి"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> నోటిఫికేషన్: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"సెట్టింగ్‌లను తెరవండి."</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 981a953..015ac90 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -45,4 +45,13 @@
 
     <!-- Show a separate icon for low and high volume on the volume dialog -->
     <bool name="config_showLowMediaVolumeIcon">true</bool>
+
+    <!-- Change the volume row tint when it is inactive, i.e. when it is being dismissed -->
+    <bool name="config_changeVolumeRowTintWhenInactive">false</bool>
+
+    <!-- The duraction of the show animation for the volume dialog in milliseconds -->
+    <integer name="config_dialogShowAnimationDurationMs">600</integer>
+
+    <!-- The duraction of the hide animation for the volume dialog in milliseconds -->
+    <integer name="config_dialogHideAnimationDurationMs">400</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c613e9c..cb6089f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"แสดงไอคอนการแจ้งเตือนลำดับความสำคัญต่ำ"</string>
     <string name="other" msgid="429768510980739978">"อื่นๆ"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"นำชิ้นส่วนออก"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"เพิ่มชิ้นส่วนต่อท้าย"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ย้ายชิ้นส่วน"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"เพิ่มชิ้นส่วน"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ย้ายไปที่ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ตัวแก้ไขการตั้งค่าด่วน"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> การแจ้งเตือน: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"เปิดการตั้งค่า"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9411957..7e6aa62 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Ipakita ang mga icon ng notification na may mababang priority"</string>
     <string name="other" msgid="429768510980739978">"Iba pa"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alisin ang tile"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"idagdag ang tile sa dulo"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Ilipat ang tile"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Magdagdag ng tile"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Ilipat sa <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor ng Mga mabilisang setting."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notification sa <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buksan ang mga setting."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4d46f93..dac352f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Düşük öncelikli bildirim simgelerini göster"</string>
     <string name="other" msgid="429768510980739978">"Diğer"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Karoyu kaldırmak için"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"Sona karo eklemek için"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Karoyu taşı"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Karo ekle"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna taşı"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna ekle"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Konum: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Hızlı ayar düzenleyicisi."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildirimi: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ayarları aç."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 399b53a..eeedac6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -889,20 +889,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Показувати значки сповіщень із низьким пріоритетом"</string>
     <string name="other" msgid="429768510980739978">"Інше"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"вилучити значок"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додати значок у кінець"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перемістити значок"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додати значок"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перемістити на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор швидких налаштувань."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Сповіщення <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Відкрити налаштування."</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 09e500d..4bd192f 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"کم ترجیحی اطلاع کے آئیکنز دکھائیں"</string>
     <string name="other" msgid="429768510980739978">"دیگر"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ٹائل ہٹائیں"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ختم کرنے کے لیے ٹائل شامل کریں"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ٹائل منتقل کریں"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ٹائل شامل کریں"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> میں منتقل کریں"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"فوری ترتیبات کا ایڈیٹر۔"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> اطلاع: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ترتیبات کھولیں۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 61b91c7..7c3728a 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Muhim boʻlmagan bildirishnoma ikonkalarini koʻrsatish"</string>
     <string name="other" msgid="429768510980739978">"Boshqa"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"katakchani olib tashlash"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"oxiriga katakcha kiritish"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Katakchani boshqa joyga olish"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Katakcha kiritish"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Bu joyga olish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bu joyga kiritish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Tezkor sozlamalar muharriri"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildirishnomasi: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Sozlamalarni ochish."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dc2a5b8..f23f742 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Hiển thị biểu tượng thông báo có mức ưu tiên thấp"</string>
     <string name="other" msgid="429768510980739978">"Khác"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"xóa ô"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"thêm ô vào cuối"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Di chuyển ô"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Thêm ô"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Di chuyển tới <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Thêm vào vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Trình chỉnh sửa cài đặt nhanh."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Thông báo của <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Mở phần cài đặt."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 71a7d8e..9b81cb0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"显示低优先级的通知图标"</string>
     <string name="other" msgid="429768510980739978">"其他"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除图块"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"将图块添加到末尾"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动图块"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"添加图块"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快捷设置编辑器。"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"打开设置。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1d763d0..facb47a 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"顯示低優先順序通知圖示"</string>
     <string name="other" msgid="429768510980739978">"其他"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"將圖塊加到結尾"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移圖塊"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"加圖塊"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移去 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"加去位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯工具。"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"開啟設定。"</string>
@@ -975,7 +968,7 @@
     <string name="auto_saver_enabled_text" msgid="7889491183116752719">"省電模式將會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
-    <string name="heap_dump_tile_name" msgid="2464189856478823046">"轉儲 SysUI 堆"</string>
+    <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 303ddd9..4e4db70 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"顯示低優先順序通知圖示"</string>
     <string name="other" msgid="429768510980739978">"其他"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"將圖塊加到結尾處"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移動圖塊"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"新增圖塊"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"新增到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯器。"</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"開啟設定。"</string>
@@ -975,7 +968,7 @@
     <string name="auto_saver_enabled_text" msgid="7889491183116752719">"省電模式會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"我知道了"</string>
-    <string name="heap_dump_tile_name" msgid="2464189856478823046">"傾印 SysUI 記憶體快照"</string>
+    <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
     <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d8eb7ad..65e9a1c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -879,20 +879,13 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Bonisa izithonjana zesaziso zokubaluleka okuncane"</string>
     <string name="other" msgid="429768510980739978">"Okunye"</string>
-    <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
-    <skip />
-    <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
-    <skip />
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"susa ithayela"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"engeza ithayela ekugcineni"</string>
+    <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hambisa ithayela"</string>
+    <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Engeza ithayela"</string>
+    <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Hambisa ku-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engeza kusikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Isikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Isihleli sezilungiselelo ezisheshayo."</string>
     <string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> isaziso: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Vula izilungiselelo."</string>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index cb49918..9b0ae1d 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -22,13 +22,15 @@
     <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
     <color name="recents_tv_text_shadow_color">#7F000000</color>
 
-    <!-- Background color for audio recording indicator (G800) -->
-    <color name="tv_audio_recording_indicator_background">#FF3C4043</color>
     <color name="tv_audio_recording_indicator_icon_background">#CC000000</color>
     <color name="tv_audio_recording_indicator_stroke">#33FFFFFF</color>
 
     <color name="red">#FFCC0000</color>
     <color name="tv_volume_dialog_background">#E61F232B</color>
     <color name="tv_volume_dialog_circle">#08FFFFFF</color>
+    <color name="tv_volume_dialog_seek_thumb_focus_ring">#1AFFFFFF</color>
+    <color name="tv_volume_dialog_seek_thumb_shadow">#40000000</color>
+    <color name="tv_volume_dialog_seek_bar_background">#A03C4043</color>
+    <color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color>
     <color name="tv_volume_dialog_accent">#FFDADCE0</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ab09a96..d63724d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -562,4 +562,13 @@
 
     <!-- Show a separate icon for low and high volume on the volume dialog -->
     <bool name="config_showLowMediaVolumeIcon">false</bool>
+
+    <!-- Change the volume row tint when it is inactive, i.e. when it is being dismissed -->
+    <bool name="config_changeVolumeRowTintWhenInactive">true</bool>
+
+    <!-- The duraction of the show animation for the volume dialog in milliseconds -->
+    <integer name="config_dialogShowAnimationDurationMs">300</integer>
+
+    <!-- The duraction of the hide animation for the volume dialog in milliseconds -->
+    <integer name="config_dialogHideAnimationDurationMs">250</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 98e8cde..48da5d9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -226,6 +226,8 @@
     <dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
     <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
 
+    <dimen name="notification_guts_header_top_padding">11dp</dimen>
+
     <!-- The height of the header in inline settings -->
     <dimen name="notification_guts_header_height">24dp</dimen>
 
@@ -482,20 +484,20 @@
     <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
     <dimen name="pull_span_min">25dp</dimen>
 
-    <dimen name="qs_tile_height">106dp</dimen>
+    <dimen name="qs_tile_height">96dp</dimen>
     <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
     <dimen name="qs_tile_layout_margin_side">18dp</dimen>
     <dimen name="qs_tile_margin_horizontal">18dp</dimen>
     <dimen name="qs_tile_margin_horizontal_two_line">2dp</dimen>
-    <dimen name="qs_tile_margin_vertical">24dp</dimen>
+    <dimen name="qs_tile_margin_vertical">2dp</dimen>
     <dimen name="qs_tile_margin_top_bottom">12dp</dimen>
     <dimen name="qs_tile_margin_top_bottom_negative">-12dp</dimen>
     <!-- The height of the qs customize header. Should be
-         (qs_panel_padding_top (48dp) +  brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
+         (qs_panel_padding_top (48dp) +  brightness_mirror_height (48dp) + qs_tile_margin_top (0dp)) -
          (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
     -->
-    <dimen name="qs_customize_header_min_height">46dp</dimen>
-    <dimen name="qs_tile_margin_top">18dp</dimen>
+    <dimen name="qs_customize_header_min_height">28dp</dimen>
+    <dimen name="qs_tile_margin_top">0dp</dimen>
     <dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
     <dimen name="qs_tile_background_size">44dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
@@ -1368,9 +1370,10 @@
     <dimen name="config_rounded_mask_size_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
 
     <!-- Output switcher panel related dimensions -->
-    <dimen name="media_output_dialog_padding_top">11dp</dimen>
+    <dimen name="media_output_dialog_list_margin">12dp</dimen>
     <dimen name="media_output_dialog_list_max_height">364dp</dimen>
     <dimen name="media_output_dialog_header_album_icon_size">52dp</dimen>
     <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
+    <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
     <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 067ac9e..e5f2ad5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -33,7 +33,6 @@
 
 import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
 import com.android.systemui.shared.recents.view.RecentsTransition;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
 
 public class WindowManagerWrapper {
 
@@ -75,7 +74,7 @@
             WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
     public static final int WINDOWING_MODE_MULTI_WINDOW =
             WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-    public static final int WINDOWING_MODE_PINNED = WindowConfiguration.WINDOWING_MODE_PINNED;
+
     public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY =
             WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY =
@@ -84,13 +83,6 @@
 
     private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
 
-    /**
-     * Forwarder to which we can add multiple pinned stack listeners. Each listener will receive
-     * updates from the window manager service.
-     */
-    private PinnedStackListenerForwarder mPinnedStackListenerForwarder =
-            new PinnedStackListenerForwarder();
-
     public static WindowManagerWrapper getInstance() {
         return sInstance;
     }
@@ -188,23 +180,6 @@
     }
 
     /**
-     * Adds a pinned stack listener, which will receive updates from the window manager service
-     * along with any other pinned stack listeners that were added via this method.
-     */
-    public void addPinnedStackListener(PinnedStackListener listener) throws RemoteException {
-        mPinnedStackListenerForwarder.addListener(listener);
-        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
-                DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
-    }
-
-    /**
-     * Removes a pinned stack listener.
-     */
-    public void removePinnedStackListener(PinnedStackListener listener) {
-        mPinnedStackListenerForwarder.removeListener(listener);
-    }
-
-    /**
      * Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
      * hierarchy.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 1b2e4c6..02a672b 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -26,6 +26,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
 
@@ -66,8 +68,10 @@
 @SysUISingleton
 final class AssistHandleReminderExpBehavior implements BehaviorController {
 
-    private static final String LEARNING_TIME_ELAPSED_KEY = "reminder_exp_learning_time_elapsed";
-    private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
+    private static final Uri LEARNING_TIME_ELAPSED_URI =
+            Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS);
+    private static final Uri LEARNING_EVENT_COUNT_URI =
+            Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT);
     private static final String LEARNED_HINT_LAST_SHOWN_KEY =
             "reminder_exp_learned_hint_last_shown";
     private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(10);
@@ -181,6 +185,7 @@
     private boolean mIsNavBarHidden;
     private boolean mIsLauncherShowing;
     private int mConsecutiveTaskSwitches;
+    @Nullable private ContentObserver mSettingObserver;
 
     /** Whether user has learned the gesture. */
     private boolean mIsLearned;
@@ -248,9 +253,22 @@
         mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
 
         mLearningTimeElapsed = Settings.Secure.getLong(
-                context.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, /* default = */ 0);
+                context.getContentResolver(),
+                Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+                /* default = */ 0);
         mLearningCount = Settings.Secure.getInt(
-                context.getContentResolver(), LEARNING_EVENT_COUNT_KEY, /* default = */ 0);
+                context.getContentResolver(),
+                Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+                /* default = */ 0);
+        mSettingObserver = new SettingsObserver(context, mHandler);
+        context.getContentResolver().registerContentObserver(
+                LEARNING_TIME_ELAPSED_URI,
+                /* notifyForDescendants = */ true,
+                mSettingObserver);
+        context.getContentResolver().registerContentObserver(
+                LEARNING_EVENT_COUNT_URI,
+                /* notifyForDescendants = */ true,
+                mSettingObserver);
         mLearnedHintLastShownEpochDay = Settings.Secure.getLong(
                 context.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, /* default = */ 0);
         mLastLearningTimestamp = mClock.currentTimeMillis();
@@ -264,8 +282,20 @@
         if (mContext != null) {
             mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
             mBootCompleteCache.get().removeListener(mBootCompleteListener);
-            Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0);
-            Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0);
+            mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+            mSettingObserver = null;
+            // putString in order to use overrideableByRestore
+            Settings.Secure.putString(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+                    Long.toString(0L),
+                    /* overrideableByRestore = */ true);
+            // putString in order to use overrideableByRestore
+            Settings.Secure.putString(
+                    mContext.getContentResolver(),
+                    Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+                    Integer.toString(0),
+                    /* overrideableByRestore = */ true);
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
             mContext = null;
         }
@@ -282,8 +312,12 @@
             return;
         }
 
-        Settings.Secure.putLong(
-                mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, ++mLearningCount);
+        // putString in order to use overrideableByRestore
+        Settings.Secure.putString(
+                mContext.getContentResolver(),
+                Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+                Integer.toString(++mLearningCount),
+                /* overrideableByRestore = */ true);
     }
 
     @Override
@@ -460,8 +494,12 @@
         mIsLearned =
                 mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
 
-        mHandler.post(() -> Settings.Secure.putLong(
-                mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed));
+        // putString in order to use overrideableByRestore
+        mHandler.post(() -> Settings.Secure.putString(
+                mContext.getContentResolver(),
+                Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+                Long.toString(mLearningTimeElapsed),
+                /* overrideableByRestore = */ true));
     }
 
     private void resetConsecutiveTaskSwitches() {
@@ -589,4 +627,32 @@
                 + "="
                 + getShowWhenTaught());
     }
+
+    private final class SettingsObserver extends ContentObserver {
+
+        private final Context mContext;
+
+        SettingsObserver(Context context, Handler handler) {
+            super(handler);
+            mContext = context;
+        }
+
+        @Override
+        public void onChange(boolean selfChange, @Nullable Uri uri) {
+            if (LEARNING_TIME_ELAPSED_URI.equals(uri)) {
+                mLastLearningTimestamp = mClock.currentTimeMillis();
+                mLearningTimeElapsed = Settings.Secure.getLong(
+                        mContext.getContentResolver(),
+                        Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+                        /* default = */ 0);
+            } else if (LEARNING_EVENT_COUNT_URI.equals(uri)) {
+                mLearningCount = Settings.Secure.getInt(
+                        mContext.getContentResolver(),
+                        Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+                        /* default = */ 0);
+            }
+
+            super.onChange(selfChange, uri);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index bde9a6e..38a191c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -309,7 +309,7 @@
             final List<FingerprintSensorProperties> fingerprintSensorProperties =
                     mFingerprintManager.getSensorProperties();
             for (FingerprintSensorProperties props : fingerprintSensorProperties) {
-                if (props.sensorType == FingerprintSensorProperties.TYPE_UDFPS) {
+                if (props.isAnyUdfpsType()) {
                     mUdfpsController = mUdfpsControllerFactory.get();
                     break;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index b610602..90b1f55 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -33,7 +33,6 @@
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
@@ -91,7 +90,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.PinnedStackListenerForwarder;
 import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -115,6 +113,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -366,6 +365,7 @@
             INotificationManager notificationManager,
             @Nullable IStatusBarService statusBarService,
             WindowManager windowManager,
+            WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps) {
         dumpManager.registerDumpable(TAG, this);
         mContext = context;
@@ -441,7 +441,7 @@
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
         try {
-            WindowManagerWrapper.getInstance().addPinnedStackListener(new BubblesImeListener());
+            windowManagerShellWrapper.addPinnedStackListener(new BubblesImeListener());
         } catch (RemoteException e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 9efc3c2..5bf1053 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 import dagger.Module;
 import dagger.Provides;
@@ -73,6 +74,7 @@
             INotificationManager notifManager,
             IStatusBarService statusBarService,
             WindowManager windowManager,
+            WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps) {
         return new BubbleController(
                 context,
@@ -96,6 +98,7 @@
                 notifManager,
                 statusBarService,
                 windowManager,
+                windowManagerShellWrapper,
                 launcherApps);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 38e12a6..c90e6b1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -66,6 +66,7 @@
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -312,6 +313,13 @@
 
     /** */
     @Provides
+    public WindowManagerWrapper providesWindowManagerWrapper() {
+        return WindowManagerWrapper.getInstance();
+    }
+
+    /** */
+    @Provides
+    @SysUISingleton
     public SystemActions providesSystemActions(Context context) {
         return new SystemActions(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaBrowserFactory.java b/packages/SystemUI/src/com/android/systemui/media/MediaBrowserFactory.java
new file mode 100644
index 0000000..aca033e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaBrowserFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.browse.MediaBrowser;
+import android.os.Bundle;
+
+import javax.inject.Inject;
+
+/**
+ * Testable wrapper around {@link MediaBrowser} constructor
+ */
+public class MediaBrowserFactory {
+    private final Context mContext;
+
+    @Inject
+    public MediaBrowserFactory(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Creates a new MediaBrowser
+     *
+     * @param serviceComponent
+     * @param callback
+     * @param rootHints
+     * @return
+     */
+    public MediaBrowser create(ComponentName serviceComponent,
+            MediaBrowser.ConnectionCallback callback, Bundle rootHints) {
+        return new MediaBrowser(mContext, serviceComponent, callback, rootHints);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 636f420..c2d6cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -174,7 +174,7 @@
         mediaManager.addListener(object : MediaDataManager.Listener {
             override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
                 addOrUpdatePlayer(key, oldKey, data)
-                val canRemove = data.isPlaying?.let { !it } ?: data.isClearable
+                val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
                 if (canRemove && !Utils.useMediaResumption(context)) {
                     // This view isn't playing, let's remove this! This happens e.g when
                     // dismissing/timing out a view. We still have the data around because
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 2bc908b..a993d00 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.media
 
-import android.content.Context
 import android.media.MediaRouter2Manager
 import android.media.session.MediaController
 import androidx.annotation.AnyThread
@@ -25,7 +24,6 @@
 import com.android.settingslib.media.LocalMediaManager
 import com.android.settingslib.media.MediaDevice
 import com.android.systemui.Dumpable
-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
@@ -34,11 +32,13 @@
 import java.util.concurrent.Executor
 import javax.inject.Inject
 
+private const val PLAYBACK_TYPE_UNKNOWN = 0
+
 /**
  * Provides information about the route (ie. device) where playback is occurring.
  */
 class MediaDeviceManager @Inject constructor(
-    private val context: Context,
+    private val controllerFactory: MediaControllerFactory,
     private val localMediaManagerFactory: LocalMediaManagerFactory,
     private val mr2manager: MediaRouter2Manager,
     @Main private val fgExecutor: Executor,
@@ -72,7 +72,7 @@
         if (entry == null || entry?.token != data.token) {
             entry?.stop()
             val controller = data.token?.let {
-                MediaController(context, it)
+                controllerFactory.create(it)
             }
             entry = Entry(key, oldKey, controller,
                     localMediaManagerFactory.create(data.packageName))
@@ -123,11 +123,12 @@
         val oldKey: String?,
         val controller: MediaController?,
         val localMediaManager: LocalMediaManager
-    ) : LocalMediaManager.DeviceCallback {
+    ) : LocalMediaManager.DeviceCallback, MediaController.Callback() {
 
         val token
             get() = controller?.sessionToken
         private var started = false
+        private var playbackType = PLAYBACK_TYPE_UNKNOWN
         private var current: MediaDevice? = null
             set(value) {
                 if (!started || value != field) {
@@ -142,6 +143,8 @@
         fun start() = bgExecutor.execute {
             localMediaManager.registerCallback(this)
             localMediaManager.startScan()
+            playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+            controller?.registerCallback(this)
             updateCurrent()
             started = true
         }
@@ -149,22 +152,37 @@
         @AnyThread
         fun stop() = bgExecutor.execute {
             started = false
+            controller?.unregisterCallback(this)
             localMediaManager.stopScan()
             localMediaManager.unregisterCallback(this)
         }
 
         fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
-            val route = controller?.let {
+            val routingSession = controller?.let {
                 mr2manager.getRoutingSessionForMediaController(it)
             }
+            val selectedRoutes = routingSession?.let {
+                mr2manager.getSelectedRoutes(it)
+            }
             with(pw) {
                 println("    current device is ${current?.name}")
                 val type = controller?.playbackInfo?.playbackType
-                println("    PlaybackType=$type (1 for local, 2 for remote)")
-                println("    route=$route")
+                println("    PlaybackType=$type (1 for local, 2 for remote) cached=$playbackType")
+                println("    routingSession=$routingSession")
+                println("    selectedRoutes=$selectedRoutes")
             }
         }
 
+        @WorkerThread
+        override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
+            val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+            if (newPlaybackType == playbackType) {
+                return
+            }
+            playbackType = newPlaybackType
+            updateCurrent()
+        }
+
         override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute {
             updateCurrent()
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 5b59214..5c1c60c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -28,6 +28,7 @@
 import android.provider.Settings
 import android.service.media.MediaBrowserService
 import android.util.Log
+import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -47,7 +48,8 @@
     private val context: Context,
     private val broadcastDispatcher: BroadcastDispatcher,
     @Background private val backgroundExecutor: Executor,
-    private val tunerService: TunerService
+    private val tunerService: TunerService,
+    private val mediaBrowserFactory: ResumeMediaBrowserFactory
 ) : MediaDataManager.Listener {
 
     private var useMediaResumption: Boolean = Utils.useMediaResumption(context)
@@ -59,7 +61,8 @@
     private var mediaBrowser: ResumeMediaBrowser? = null
     private var currentUserId: Int = context.userId
 
-    private val userChangeReceiver = object : BroadcastReceiver() {
+    @VisibleForTesting
+    val userChangeReceiver = object : BroadcastReceiver() {
         override fun onReceive(context: Context, intent: Intent) {
             if (Intent.ACTION_USER_UNLOCKED == intent.action) {
                 loadMediaResumptionControls()
@@ -152,7 +155,7 @@
 
         resumeComponents.forEach {
             if (!blockedApps.contains(it.packageName)) {
-                val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it)
+                val browser = mediaBrowserFactory.create(mediaBrowserCallback, it)
                 browser.findRecentMedia()
             }
         }
@@ -193,14 +196,10 @@
     private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
         Log.d(TAG, "Testing if we can connect to $componentName")
         mediaBrowser?.disconnect()
-        mediaBrowser = ResumeMediaBrowser(context,
+        mediaBrowser = mediaBrowserFactory.create(
                 object : ResumeMediaBrowser.Callback() {
                     override fun onConnected() {
-                        Log.d(TAG, "yes we can resume with $componentName")
-                        mediaDataManager.setResumeAction(key, getResumeAction(componentName))
-                        updateResumptionList(componentName)
-                        mediaBrowser?.disconnect()
-                        mediaBrowser = null
+                        Log.d(TAG, "Connected to $componentName")
                     }
 
                     override fun onError() {
@@ -209,6 +208,19 @@
                         mediaBrowser?.disconnect()
                         mediaBrowser = null
                     }
+
+                    override fun addTrack(
+                        desc: MediaDescription,
+                        component: ComponentName,
+                        browser: ResumeMediaBrowser
+                    ) {
+                        // Since this is a test, just save the component for later
+                        Log.d(TAG, "Can get resumable media from $componentName")
+                        mediaDataManager.setResumeAction(key, getResumeAction(componentName))
+                        updateResumptionList(componentName)
+                        mediaBrowser?.disconnect()
+                        mediaBrowser = null
+                    }
                 },
                 componentName)
         mediaBrowser?.testConnection()
@@ -245,7 +257,7 @@
     private fun getResumeAction(componentName: ComponentName): Runnable {
         return Runnable {
             mediaBrowser?.disconnect()
-            mediaBrowser = ResumeMediaBrowser(context,
+            mediaBrowser = mediaBrowserFactory.create(
                 object : ResumeMediaBrowser.Callback() {
                     override fun onConnected() {
                         if (mediaBrowser?.token == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 6bd5274..51dbfa7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -126,6 +126,7 @@
 
         fun destroy() {
             mediaController?.unregisterCallback(this)
+            cancellation?.run()
         }
 
         override fun onPlaybackStateChanged(state: PlaybackState?) {
@@ -182,4 +183,4 @@
             cancellation = null
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index 68b6785..a4d4436 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -30,6 +30,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.List;
 
 /**
@@ -46,6 +48,7 @@
     private static final String TAG = "ResumeMediaBrowser";
     private final Context mContext;
     private final Callback mCallback;
+    private MediaBrowserFactory mBrowserFactory;
     private MediaBrowser mMediaBrowser;
     private ComponentName mComponentName;
 
@@ -55,10 +58,12 @@
      * @param callback used to report media items found
      * @param componentName Component name of the MediaBrowserService this browser will connect to
      */
-    public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName) {
+    public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName,
+            MediaBrowserFactory browserFactory) {
         mContext = context;
         mCallback = callback;
         mComponentName = componentName;
+        mBrowserFactory = browserFactory;
     }
 
     /**
@@ -74,7 +79,7 @@
         disconnect();
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = new MediaBrowser(mContext,
+        mMediaBrowser = mBrowserFactory.create(
                 mComponentName,
                 mConnectionCallback,
                 rootHints);
@@ -88,17 +93,19 @@
                 List<MediaBrowser.MediaItem> children) {
             if (children.size() == 0) {
                 Log.d(TAG, "No children found for " + mComponentName);
-                return;
-            }
-            // We ask apps to return a playable item as the first child when sending
-            // a request with EXTRA_RECENT; if they don't, no resume controls
-            MediaBrowser.MediaItem child = children.get(0);
-            MediaDescription desc = child.getDescription();
-            if (child.isPlayable() && mMediaBrowser != null) {
-                mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
-                        ResumeMediaBrowser.this);
+                mCallback.onError();
             } else {
-                Log.d(TAG, "Child found but not playable for " + mComponentName);
+                // We ask apps to return a playable item as the first child when sending
+                // a request with EXTRA_RECENT; if they don't, no resume controls
+                MediaBrowser.MediaItem child = children.get(0);
+                MediaDescription desc = child.getDescription();
+                if (child.isPlayable() && mMediaBrowser != null) {
+                    mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
+                            ResumeMediaBrowser.this);
+                } else {
+                    Log.d(TAG, "Child found but not playable for " + mComponentName);
+                    mCallback.onError();
+                }
             }
             disconnect();
         }
@@ -131,7 +138,7 @@
             Log.d(TAG, "Service connected for " + mComponentName);
             if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
                 String root = mMediaBrowser.getRoot();
-                if (!TextUtils.isEmpty(root)) {
+                if (!TextUtils.isEmpty(root) && mMediaBrowser != null) {
                     mCallback.onConnected();
                     mMediaBrowser.subscribe(root, mSubscriptionCallback);
                     return;
@@ -182,7 +189,7 @@
         disconnect();
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = new MediaBrowser(mContext, mComponentName,
+        mMediaBrowser = mBrowserFactory.create(mComponentName,
                 new MediaBrowser.ConnectionCallback() {
                     @Override
                     public void onConnected() {
@@ -192,7 +199,7 @@
                             return;
                         }
                         MediaSession.Token token = mMediaBrowser.getSessionToken();
-                        MediaController controller = new MediaController(mContext, token);
+                        MediaController controller = createMediaController(token);
                         controller.getTransportControls();
                         controller.getTransportControls().prepare();
                         controller.getTransportControls().play();
@@ -212,6 +219,11 @@
         mMediaBrowser.connect();
     }
 
+    @VisibleForTesting
+    protected MediaController createMediaController(MediaSession.Token token) {
+        return new MediaController(mContext, token);
+    }
+
     /**
      * Get the media session token
      * @return the token, or null if the MediaBrowser is null or disconnected
@@ -235,42 +247,19 @@
 
     /**
      * Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser.
-     * ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
-     * depending on whether it was successful.
+     * If it can connect, ResumeMediaBrowser.Callback#onConnected will be called. If valid media is
+     * found, then ResumeMediaBrowser.Callback#addTrack will also be called. This allows for more
+     * detailed logging if the service has issues. If it cannot connect, or cannot find valid media,
+     * then ResumeMediaBrowser.Callback#onError will be called.
      * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
      */
     public void testConnection() {
         disconnect();
-        final MediaBrowser.ConnectionCallback connectionCallback =
-                new MediaBrowser.ConnectionCallback() {
-                    @Override
-                    public void onConnected() {
-                        Log.d(TAG, "connected");
-                        if (mMediaBrowser == null || !mMediaBrowser.isConnected()
-                                || TextUtils.isEmpty(mMediaBrowser.getRoot())) {
-                            mCallback.onError();
-                        } else {
-                            mCallback.onConnected();
-                        }
-                    }
-
-                    @Override
-                    public void onConnectionSuspended() {
-                        Log.d(TAG, "suspended");
-                        mCallback.onError();
-                    }
-
-                    @Override
-                    public void onConnectionFailed() {
-                        Log.d(TAG, "failed");
-                        mCallback.onError();
-                    }
-                };
         Bundle rootHints = new Bundle();
         rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
-        mMediaBrowser = new MediaBrowser(mContext,
+        mMediaBrowser = mBrowserFactory.create(
                 mComponentName,
-                connectionCallback,
+                mConnectionCallback,
                 rootHints);
         mMediaBrowser.connect();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java
new file mode 100644
index 0000000..2261aa5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import javax.inject.Inject;
+
+/**
+ * Testable wrapper around {@link ResumeMediaBrowser} constructor
+ */
+public class ResumeMediaBrowserFactory {
+    private final Context mContext;
+    private final MediaBrowserFactory mBrowserFactory;
+
+    @Inject
+    public ResumeMediaBrowserFactory(Context context, MediaBrowserFactory browserFactory) {
+        mContext = context;
+        mBrowserFactory = browserFactory;
+    }
+
+    /**
+     * Creates a new ResumeMediaBrowser.
+     *
+     * @param callback will be called on connection or error, and addTrack when media item found
+     * @param componentName component to browse
+     * @return
+     */
+    public ResumeMediaBrowser create(ResumeMediaBrowser.Callback callback,
+            ComponentName componentName) {
+        return new ResumeMediaBrowser(mContext, callback, componentName, mBrowserFactory);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 9fc64d5..9b6a9ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -42,7 +42,7 @@
 public class MediaOutputAdapter extends MediaOutputBaseAdapter {
 
     private static final String TAG = "MediaOutputAdapter";
-    private static final int PAIR_NEW = 1;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     public MediaOutputAdapter(MediaOutputController controller) {
         super(controller);
@@ -58,11 +58,14 @@
 
     @Override
     public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
-        if (mController.isZeroMode() && position == (mController.getMediaDevices().size())) {
-            viewHolder.onBind(PAIR_NEW);
-        } else if (position < (mController.getMediaDevices().size())) {
-            viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position));
-        } else {
+        final int size = mController.getMediaDevices().size();
+        if (mController.isZeroMode() && position == size) {
+            viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
+                    true /* bottomMargin */);
+        } else if (position < size) {
+            viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
+                    position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
+        } else if (DEBUG) {
             Log.d(TAG, "Incorrect position: " + position);
         }
     }
@@ -83,7 +86,7 @@
     }
 
     void onItemClick(int customizedItem) {
-        if (customizedItem == PAIR_NEW) {
+        if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
             mController.launchBluetoothPairing();
         }
     }
@@ -112,51 +115,49 @@
         }
 
         @Override
-        void onBind(MediaDevice device) {
-            super.onBind(device);
+        void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
+            super.onBind(device, topMargin, bottomMargin);
             if (mController.isTransferring()) {
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING
                         && !mController.hasAdjustVolumeUserRestriction()) {
-                    setTwoLineLayout(device, true);
-                    mProgressBar.setVisibility(View.VISIBLE);
-                    mSeekBar.setVisibility(View.GONE);
-                    mSubTitleText.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, true /* bFocused */,
+                            false /* showSeekBar*/, true /* showProgressBar */,
+                            false /* showSubtitle */);
                 } else {
-                    setSingleLineLayout(getItemTitle(device), false);
+                    setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                 }
             } else {
                 // Set different layout for each device
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
-                    setTwoLineLayout(device, false);
-                    mSubTitleText.setVisibility(View.VISIBLE);
-                    mSeekBar.setVisibility(View.GONE);
-                    mProgressBar.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, false /* bFocused */,
+                            false /* showSeekBar*/, false /* showProgressBar */,
+                            true /* showSubtitle */);
                     mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                     mFrameLayout.setOnClickListener(v -> onItemClick(device));
                 } else if (!mController.hasAdjustVolumeUserRestriction()
                         && isCurrentConnected(device)) {
-                    setTwoLineLayout(device, true);
-                    mSeekBar.setVisibility(View.VISIBLE);
-                    mProgressBar.setVisibility(View.GONE);
-                    mSubTitleText.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, true /* bFocused */,
+                            true /* showSeekBar*/, false /* showProgressBar */,
+                            false /* showSubtitle */);
                     initSeekbar(device);
                 } else {
-                    setSingleLineLayout(getItemTitle(device), false);
+                    setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                     mFrameLayout.setOnClickListener(v -> onItemClick(device));
                 }
             }
         }
 
         @Override
-        void onBind(int customizedItem) {
-            if (customizedItem == PAIR_NEW) {
+        void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+            super.onBind(customizedItem, topMargin, bottomMargin);
+            if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
-                        false);
+                        false /* bFocused */);
                 final Drawable d = mContext.getDrawable(R.drawable.ic_add);
                 d.setColorFilter(new PorterDuffColorFilter(
                         Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
                 mTitleIcon.setImageDrawable(d);
-                mFrameLayout.setOnClickListener(v -> onItemClick(PAIR_NEW));
+                mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 7579c25..01dc6c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -44,9 +44,12 @@
     private static final String FONT_SELECTED_TITLE = "sans-serif-medium";
     private static final String FONT_TITLE = "sans-serif";
 
+    static final int CUSTOMIZED_ITEM_PAIR_NEW = 1;
+
     final MediaOutputController mController;
 
     private boolean mIsDragging;
+    private int mMargin;
 
     Context mContext;
     View mHolderView;
@@ -60,6 +63,8 @@
     public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
             int viewType) {
         mContext = viewGroup.getContext();
+        mMargin = mContext.getResources().getDimensionPixelSize(
+                R.dimen.media_output_dialog_list_margin);
         mHolderView = LayoutInflater.from(mContext).inflate(R.layout.media_output_list_item,
                 viewGroup, false);
 
@@ -106,12 +111,26 @@
             mSeekBar = view.requireViewById(R.id.volume_seekbar);
         }
 
-        void onBind(MediaDevice device) {
+        void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
             mTitleIcon.setImageIcon(mController.getDeviceIconCompat(device).toIcon(mContext));
+            setMargin(topMargin, bottomMargin);
         }
 
-        void onBind(int customizedItem) { }
+        void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+            setMargin(topMargin, bottomMargin);
+        }
 
+        private void setMargin(boolean topMargin, boolean bottomMargin) {
+            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout
+                    .getLayoutParams();
+            if (topMargin) {
+                params.topMargin = mMargin;
+            }
+            if (bottomMargin) {
+                params.bottomMargin = mMargin;
+            }
+            mFrameLayout.setLayoutParams(params);
+        }
         void setSingleLineLayout(CharSequence title, boolean bFocused) {
             mTitleText.setVisibility(View.VISIBLE);
             mTwoLineLayout.setVisibility(View.GONE);
@@ -123,10 +142,19 @@
             }
         }
 
-        void setTwoLineLayout(MediaDevice device, boolean bFocused) {
+        void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused,
+                boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {
             mTitleText.setVisibility(View.GONE);
             mTwoLineLayout.setVisibility(View.VISIBLE);
-            mTwoLineTitleText.setText(getItemTitle(device));
+            mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
+            mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
+            mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+            if (device == null) {
+                mTwoLineTitleText.setText(title);
+            } else {
+                mTwoLineTitleText.setText(getItemTitle(device));
+            }
+
             if (bFocused) {
                 mTwoLineTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE,
                         Typeface.NORMAL));
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index f8f4f4d..ebca8a7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -33,7 +33,6 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.Button;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -69,12 +68,9 @@
     private LinearLayout mDeviceListLayout;
     private Button mDoneButton;
     private Button mStopButton;
-    private View mListBottomPadding;
     private int mListMaxHeight;
 
     MediaOutputBaseAdapter mAdapter;
-    FrameLayout mGroupItemController;
-    View mGroupDivider;
 
     private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
         // Set max height for list
@@ -114,12 +110,9 @@
         mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
         mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
         mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
-        mGroupItemController = mDialogView.requireViewById(R.id.group_item_controller);
-        mGroupDivider = mDialogView.requireViewById(R.id.group_item_divider);
         mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
         mDoneButton = mDialogView.requireViewById(R.id.done);
         mStopButton = mDialogView.requireViewById(R.id.stop);
-        mListBottomPadding = mDialogView.requireViewById(R.id.list_bottom_padding);
 
         mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
                 mDeviceListLayoutListener);
@@ -162,7 +155,9 @@
         }
         if (mHeaderIcon.getVisibility() == View.VISIBLE) {
             final int size = getHeaderIconSize();
-            mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size, size));
+            final int padding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.media_output_dialog_header_icon_padding);
+            mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
         }
         // Update title and subtitle
         mHeaderTitle.setText(getHeaderText());
@@ -178,12 +173,8 @@
         if (!mAdapter.isDragging()) {
             mAdapter.notifyDataSetChanged();
         }
-        // Add extra padding when device amount is less than 6
-        if (mMediaOutputController.getMediaDevices().size() < 6) {
-            mListBottomPadding.setVisibility(View.VISIBLE);
-        } else {
-            mListBottomPadding.setVisibility(View.GONE);
-        }
+        // Show when remote media session is available
+        mStopButton.setVisibility(getStopButtonVisibility());
     }
 
     abstract int getHeaderIconRes();
@@ -196,6 +187,8 @@
 
     abstract CharSequence getHeaderSubtitle();
 
+    abstract int getStopButtonVisibility();
+
     @Override
     public void onMediaChanged() {
         mMainThreadHandler.post(() -> refresh());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 64d20a27..b1f1bda 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.media.MediaMetadata;
+import android.media.MediaRoute2Info;
 import android.media.RoutingSessionInfo;
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
@@ -63,7 +64,7 @@
 public class MediaOutputController implements LocalMediaManager.DeviceCallback{
 
     private static final String TAG = "MediaOutputController";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final String mPackageName;
     private final Context mContext;
@@ -406,6 +407,14 @@
         mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true);
     }
 
+    boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
+        final List<String> features = device.getFeatures();
+        return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
+    }
+
     private final MediaController.Callback mCb = new MediaController.Callback() {
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index ac9d8ce..a892a12 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -45,8 +45,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mGroupItemController.setVisibility(View.GONE);
-        mGroupDivider.setVisibility(View.GONE);
     }
 
     @Override
@@ -74,4 +72,10 @@
     CharSequence getHeaderSubtitle() {
         return mMediaOutputController.getHeaderSubTitle();
     }
+
+    @Override
+    int getStopButtonVisibility() {
+        return mMediaOutputController.isActiveRemoteDevice(
+                mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index bc1dca5..4cdca4c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -33,10 +33,22 @@
     private val shadeController: ShadeController,
     private val starter: ActivityStarter
 ) {
+    companion object {
+        var mediaOutputDialog: MediaOutputDialog? = null
+    }
+
     /** Creates a [MediaOutputDialog] for the given package. */
     fun create(packageName: String, aboveStatusBar: Boolean) {
-        MediaOutputController(context, packageName, mediaSessionManager, lbm, shadeController,
-                starter).run {
+        mediaOutputDialog?.dismiss()
+
+        mediaOutputDialog = MediaOutputController(context, packageName, mediaSessionManager, lbm,
+                shadeController, starter).run {
             MediaOutputDialog(context, aboveStatusBar, this) }
     }
+
+    /** dismiss [MediaOutputDialog] if exist. */
+    fun dismiss() {
+        mediaOutputDialog?.dismiss()
+        mediaOutputDialog = null
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
index b068370..2b11550 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/Pip.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
@@ -16,24 +16,21 @@
 
 package com.android.systemui.pip;
 
-import android.content.res.Configuration;
+import android.app.ActivityManager;
+import android.content.ComponentName;
 import android.media.session.MediaController;
 
+import com.android.systemui.pip.phone.PipTouchHandler;
 import com.android.systemui.pip.tv.PipController;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * Interface to engage picture in picture feature.
  */
 public interface Pip {
     /**
-     * Called when showing Pip menu.
-     */
-    void showPictureInPictureMenu();
-
-    /**
      * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called.
      * whenever receiving notification on changes in PIP.
      */
@@ -53,6 +50,14 @@
     }
 
     /**
+     * Dump the current state and information if need.
+     *
+     * @param pw The stream to dump information to.
+     */
+    default void dump(PrintWriter pw) {
+    }
+
+    /**
      * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
      */
     default void expandPip() {
@@ -64,7 +69,11 @@
      * @return The state of defined in PipController.
      */
     default int getPlaybackState() {
-        return 0;
+        return -1;
+    }
+
+    default PipTouchHandler getPipTouchHandler() {
+        return null;
     }
 
     /**
@@ -95,9 +104,61 @@
     }
 
     /**
-     * Called when configuration change invoked.
+     * Called whenever an Activity is moved to the pinned stack from another stack.
      */
-    void onConfigurationChanged(Configuration newConfig);
+    default void onActivityPinned(String packageName) {
+    }
+
+    /**
+     * Called whenever an Activity is moved from the pinned stack to another stack
+     */
+    default void onActivityUnpinned(ComponentName topActivity) {
+    }
+
+    /**
+     * Called whenever IActivityManager.startActivity is called on an activity that is already
+     * running, but the task is either brought to the front or a new Intent is delivered to it.
+     *
+     * @param task        information about the task the activity was relaunched into
+     * @param clearedTask whether or not the launch activity also cleared the task as a part of
+     *                    starting
+     */
+    default void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+            boolean clearedTask) {
+    }
+
+    /**
+     * Called when display size or font size of settings changed
+     */
+    default void onDensityOrFontScaleChanged() {
+    }
+
+    /**
+     * Called when overlay package change invoked.
+     */
+    default void onOverlayChanged() {
+    }
+
+    /**
+     * Registers the session listener for the current user.
+     */
+    default void registerSessionListenerForCurrentUser() {
+    }
+
+    /**
+     * Called when SysUI state changed.
+     *
+     * @param isSysUiStateValid Is SysUI state valid or not.
+     * @param flag Current SysUI state.
+     */
+    default void onSystemUiStateChanged(boolean isSysUiStateValid, int flag) {
+    }
+
+    /**
+     * Called when task stack changed.
+     */
+    default void onTaskStackChanged() {
+    }
 
     /**
      * Removes a {@link PipController.Listener} from PipController.
@@ -137,6 +198,14 @@
     }
 
     /**
+     * Registers the pinned stack animation listener.
+     *
+     * @param callback The callback of pinned stack animation.
+     */
+    default void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+    }
+
+    /**
      * Set the pinned stack with {@link PipAnimationController.AnimationType}
      *
      * @param animationType The pre-defined {@link PipAnimationController.AnimationType}
@@ -145,12 +214,9 @@
     }
 
     /**
-     * Registers the pinned stack animation listener.
-     *
-     * @param listener The listener of pinned stack animation.
+     * Called when showing Pip menu.
      */
-    default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
-    }
+    void showPictureInPictureMenu();
 
     /**
      * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called.
@@ -159,12 +225,4 @@
      */
     default void suspendPipResizing(int reason) {
     }
-
-    /**
-     * Dump the current state and information if need.
-     *
-     * @param pw The stream to dump information to.
-     */
-    default void dump(PrintWriter pw) {
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index 3e98169..fc724cb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -24,16 +24,14 @@
 import android.view.SurfaceControl;
 
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.wm.shell.R;
 
 /**
  * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
  */
 @SysUISingleton
-public class PipSurfaceTransactionHelper implements ConfigurationController.ConfigurationListener {
+public class PipSurfaceTransactionHelper {
 
-    private final Context mContext;
     private final boolean mEnableCornerRadius;
     private int mCornerRadius;
 
@@ -44,17 +42,21 @@
     private final RectF mTmpDestinationRectF = new RectF();
     private final Rect mTmpDestinationRect = new Rect();
 
-    public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) {
+    public PipSurfaceTransactionHelper(Context context) {
         final Resources res = context.getResources();
-        mContext = context;
         mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner);
-        configController.addCallback(this);
     }
 
-    @Override
-    public void onDensityOrFontScaleChanged() {
-        final Resources res = mContext.getResources();
-        mCornerRadius = res.getDimensionPixelSize(R.dimen.pip_corner_radius);
+    /**
+     * Called when display size or font size of settings changed
+     *
+     * @param context the current context
+     */
+    public void onDensityOrFontScaleChanged(Context context) {
+        if (mEnableCornerRadius) {
+            final Resources res = context.getResources();
+            mCornerRadius = res.getDimensionPixelSize(R.dimen.pip_corner_radius);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 6cc0cd8..9cf2751 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -130,7 +130,6 @@
         }
     }
 
-    private final Context mContext;
     private final Handler mMainHandler;
     private final Handler mUpdateHandler;
     private final PipBoundsHandler mPipBoundsHandler;
@@ -249,7 +248,6 @@
             @NonNull DisplayController displayController,
             @NonNull PipUiEventLogger pipUiEventLogger,
             @NonNull ShellTaskOrganizer shellTaskOrganizer) {
-        mContext = context;
         mMainHandler = new Handler(Looper.getMainLooper());
         mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
         mPipBoundsHandler = boundsHandler;
@@ -565,8 +563,8 @@
         if (Looper.getMainLooper() != Looper.myLooper()) {
             throw new RuntimeException("PipMenuView needs to be attached on the main thread.");
         }
-
-        mPipViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
+        final Context context = menuView.getContext();
+        mPipViewHost = new SurfaceControlViewHost(context, context.getDisplay(),
                 (android.os.Binder) null);
         mPipMenuSurface = mPipViewHost.getSurfacePackage().getSurfaceControl();
         SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
@@ -659,6 +657,13 @@
     }
 
     /**
+     * Called when display size or font size of settings changed
+     */
+    public void onDensityOrFontScaleChanged(Context context) {
+        mSurfaceTransactionHelper.onDensityOrFontScaleChanged(context);
+    }
+
+    /**
      * TODO(b/152809058): consolidate the display info handling logic in SysUI
      *
      * @param destinationBoundsOut the current destination bounds will be populated to this param
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
index 8a2e9e2..6253043 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
@@ -16,55 +16,37 @@
 
 package com.android.systemui.pip.phone;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
 import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.app.IActivityManager;
 import android.app.RemoteAction;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
-import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
-import android.util.Pair;
 import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
 import android.window.WindowContainerTransaction;
 
-import com.android.systemui.Dependency;
-import com.android.systemui.UiOffloadThread;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.shared.system.PinnedStackListenerForwarder;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * Manages the picture-in-picture (PIP) UI and states for Phones.
@@ -74,7 +56,6 @@
     private static final String TAG = "PipController";
 
     private Context mContext;
-    private IActivityManager mActivityManager;
     private Handler mHandler = new Handler();
 
     private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
@@ -83,13 +64,13 @@
     protected final Rect mReentryBounds = new Rect();
 
     private DisplayController mDisplayController;
-    private InputConsumerController mInputConsumerController;
     private PipAppOpsListener mAppOpsListener;
     private PipBoundsHandler mPipBoundsHandler;
     private PipMediaController mMediaController;
     private PipTouchHandler mTouchHandler;
-    private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
-    private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
+    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
+    private WindowManagerShellWrapper mWindowManagerShellWrapper;
+
     private boolean mIsInFixedRotation;
 
     protected PipMenuActivityController mMenuController;
@@ -156,50 +137,10 @@
             };
 
     /**
-     * Handler for system task stack changes.
-     */
-    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-        @Override
-        public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
-            mTouchHandler.onActivityPinned();
-            mMediaController.onActivityPinned();
-            mMenuController.onActivityPinned();
-            mAppOpsListener.onActivityPinned(packageName);
-
-            Dependency.get(UiOffloadThread.class).execute(() -> {
-                WindowManagerWrapper.getInstance().setPipVisibility(true);
-            });
-        }
-
-        @Override
-        public void onActivityUnpinned() {
-            final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPipActivity(
-                    mContext, mActivityManager);
-            final ComponentName topActivity = topPipActivityInfo.first;
-            mMenuController.onActivityUnpinned();
-            mTouchHandler.onActivityUnpinned(topActivity);
-            mAppOpsListener.onActivityUnpinned();
-
-            Dependency.get(UiOffloadThread.class).execute(() -> {
-                WindowManagerWrapper.getInstance().setPipVisibility(topActivity != null);
-            });
-        }
-
-        @Override
-        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-                boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
-            if (task.configuration.windowConfiguration.getWindowingMode()
-                    != WINDOWING_MODE_PINNED) {
-                return;
-            }
-            mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
-        }
-    };
-
-    /**
      * Handler for messages from the PIP controller.
      */
-    private class PipControllerPinnedStackListener extends PinnedStackListener {
+    private class PipControllerPinnedStackListener extends
+            PinnedStackListenerForwarder.PinnedStackListener {
         @Override
         public void onListenerRegistered(IPinnedStackController controller) {
             mHandler.post(() -> mTouchHandler.setPinnedStackController(controller));
@@ -237,7 +178,10 @@
 
         @Override
         public void onConfigurationChanged() {
-            mHandler.post(() -> mPipBoundsHandler.onConfigurationChanged(mContext));
+            mHandler.post(() -> {
+                mPipBoundsHandler.onConfigurationChanged(mContext);
+                mTouchHandler.onConfigurationChanged();
+            });
         }
 
         @Override
@@ -249,52 +193,36 @@
         }
     }
 
-    public ConfigurationController.ConfigurationListener mOverlayChangedListener =
-            new ConfigurationController.ConfigurationListener() {
-                @Override
-                public void onOverlayChanged() {
-                    mHandler.post(() -> {
-                        mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
-                        updateMovementBounds(null /* toBounds */,
-                                false /* fromRotation */, false /* fromImeAdjustment */,
-                                false /* fromShelfAdjustment */,
-                                null /* windowContainerTransaction */);
-                    });
-                }
-            };
-
-    public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
-            ConfigurationController configController,
-            DeviceConfigProxy deviceConfig,
+    public PipController(Context context,
             DisplayController displayController,
-            FloatingContentCoordinator floatingContentCoordinator,
-            SysUiState sysUiState,
+            PipAppOpsListener pipAppOpsListener,
             PipBoundsHandler pipBoundsHandler,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+            PipMediaController pipMediaController,
+            PipMenuActivityController pipMenuActivityController,
             PipTaskOrganizer pipTaskOrganizer,
-            PipUiEventLogger pipUiEventLogger) {
+            PipTouchHandler pipTouchHandler,
+            WindowManagerShellWrapper windowManagerShellWrapper
+    ) {
         mContext = context;
-        mActivityManager = ActivityManager.getService();
 
         if (PipUtils.hasSystemFeature(mContext)) {
-            initController(context, broadcastDispatcher, configController, deviceConfig,
-                    displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
-                    pipSurfaceTransactionHelper, pipTaskOrganizer, pipUiEventLogger);
+            initController(context, displayController, pipAppOpsListener, pipBoundsHandler,
+                    pipMediaController, pipMenuActivityController, pipTaskOrganizer,
+                    pipTouchHandler, windowManagerShellWrapper);
         } else {
             Log.w(TAG, "Device not support PIP feature");
         }
     }
 
-    private void initController(Context context, BroadcastDispatcher broadcastDispatcher,
-            ConfigurationController configController,
-            DeviceConfigProxy deviceConfig,
+    private void initController(Context context,
             DisplayController displayController,
-            FloatingContentCoordinator floatingContentCoordinator,
-            SysUiState sysUiState,
+            PipAppOpsListener pipAppOpsListener,
             PipBoundsHandler pipBoundsHandler,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+            PipMediaController pipMediaController,
+            PipMenuActivityController pipMenuActivityController,
             PipTaskOrganizer pipTaskOrganizer,
-            PipUiEventLogger pipUiEventLogger) {
+            PipTouchHandler pipTouchHandler,
+            WindowManagerShellWrapper windowManagerShellWrapper) {
 
         // Ensure that we are the primary user's SystemUI.
         final int processUser = UserManager.get(context).getUserHandle();
@@ -302,28 +230,15 @@
             throw new IllegalStateException("Non-primary Pip component not currently supported.");
         }
 
-        try {
-            WindowManagerWrapper.getInstance().addPinnedStackListener(
-                    new PipControllerPinnedStackListener());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to register pinned stack listener", e);
-        }
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
-
+        mWindowManagerShellWrapper = windowManagerShellWrapper;
         mDisplayController = displayController;
         mPipBoundsHandler = pipBoundsHandler;
-        mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
         mPipTaskOrganizer = pipTaskOrganizer;
         mPipTaskOrganizer.registerPipTransitionCallback(this);
-        mInputConsumerController = InputConsumerController.getPipInputConsumer();
-        mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
-        mMenuController = new PipMenuActivityController(context,
-                mMediaController, mInputConsumerController, mPipTaskOrganizer);
-        mTouchHandler = new PipTouchHandler(context, mActivityManager,
-                mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
-                floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
-        mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
-                mTouchHandler.getMotionHelper());
+        mMediaController = pipMediaController;
+        mMenuController = pipMenuActivityController;
+        mTouchHandler = pipTouchHandler;
+        mAppOpsListener = pipAppOpsListener;
         displayController.addDisplayChangingController(mRotationController);
         displayController.addDisplayWindowListener(mFixedRotationListener);
 
@@ -333,26 +248,69 @@
         context.getDisplay().getDisplayInfo(displayInfo);
         mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
 
-        configController.addCallback(mOverlayChangedListener);
-
         try {
-            RootTaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
-                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (taskInfo != null) {
-                // If SystemUI restart, and it already existed a pinned stack,
-                // register the pip input consumer to ensure touch can send to it.
-                mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
-            }
-        } catch (RemoteException | UnsupportedOperationException e) {
-            e.printStackTrace();
+            mWindowManagerShellWrapper.addPinnedStackListener(
+                    new PipControllerPinnedStackListener());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
         }
     }
 
-    /**
-     * Updates the PIP per configuration changed.
-     */
-    public void onConfigurationChanged(Configuration newConfig) {
-        mTouchHandler.onConfigurationChanged();
+    @Override
+    public void onDensityOrFontScaleChanged() {
+        mHandler.post(() -> {
+            mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
+        });
+    }
+
+    @Override
+    public void onActivityPinned(String packageName) {
+        mHandler.post(() -> {
+            mTouchHandler.onActivityPinned();
+            mMediaController.onActivityPinned();
+            mMenuController.onActivityPinned();
+            mAppOpsListener.onActivityPinned(packageName);
+        });
+    }
+
+    @Override
+    public void onActivityUnpinned(ComponentName topActivity) {
+        mHandler.post(() -> {
+            mMenuController.onActivityUnpinned();
+            mTouchHandler.onActivityUnpinned(topActivity);
+            mAppOpsListener.onActivityUnpinned();
+        });
+    }
+
+    @Override
+    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+            boolean clearedTask) {
+        if (task.configuration.windowConfiguration.getWindowingMode()
+                != WINDOWING_MODE_PINNED) {
+            return;
+        }
+        mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
+    }
+
+    @Override
+    public void onOverlayChanged() {
+        mHandler.post(() -> {
+            mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
+            updateMovementBounds(null /* toBounds */,
+                    false /* fromRotation */, false /* fromImeAdjustment */,
+                    false /* fromShelfAdjustment */,
+                    null /* windowContainerTransaction */);
+        });
+    }
+
+    @Override
+    public void registerSessionListenerForCurrentUser() {
+        mMediaController.registerSessionListenerForCurrentUser();
+    }
+
+    @Override
+    public void onSystemUiStateChanged(boolean isValidState, int flag) {
+        mTouchHandler.onSystemUiStateChanged(isValidState);
     }
 
     /**
@@ -363,6 +321,11 @@
         mTouchHandler.getMotionHelper().expandLeavePip(false /* skipAnimation */);
     }
 
+    @Override
+    public PipTouchHandler getPipTouchHandler() {
+        return mTouchHandler;
+    }
+
     /**
      * Hides the PIP menu.
      */
@@ -408,8 +371,8 @@
     }
 
     @Override
-    public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
-        mHandler.post(() -> mPinnedStackAnimationRecentsListener = listener);
+    public void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+        mHandler.post(() -> mPinnedStackAnimationRecentsCallback = callback);
     }
 
     @Override
@@ -421,12 +384,8 @@
         }
         // Disable touches while the animation is running
         mTouchHandler.setTouchEnabled(false);
-        if (mPinnedStackAnimationRecentsListener != null) {
-            try {
-                mPinnedStackAnimationRecentsListener.onPinnedStackAnimationStarted();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to callback recents", e);
-            }
+        if (mPinnedStackAnimationRecentsCallback != null) {
+            mPinnedStackAnimationRecentsCallback.accept(true);
         }
     }
 
@@ -477,7 +436,6 @@
     public void dump(PrintWriter pw) {
         final String innerPrefix = "  ";
         pw.println(TAG);
-        mInputConsumerController.dump(pw, innerPrefix);
         mMenuController.dump(pw, innerPrefix);
         mTouchHandler.dump(pw, innerPrefix);
         mPipBoundsHandler.dump(pw, innerPrefix);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index 361aafa..a5b5092 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -26,19 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
 import android.media.session.PlaybackState;
 import android.os.UserHandle;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.statusbar.policy.UserInfoController;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -101,17 +96,11 @@
     };
 
     private final MediaSessionManager.OnActiveSessionsChangedListener mSessionsChangedListener =
-            new OnActiveSessionsChangedListener() {
-        @Override
-        public void onActiveSessionsChanged(List<MediaController> controllers) {
-            resolveActiveMediaController(controllers);
-        }
-    };
+            controllers -> resolveActiveMediaController(controllers);
 
     private ArrayList<ActionListener> mListeners = new ArrayList<>();
 
-    public PipMediaController(Context context, IActivityManager activityManager,
-            BroadcastDispatcher broadcastDispatcher) {
+    public PipMediaController(Context context, IActivityManager activityManager) {
         mContext = context;
         mActivityManager = activityManager;
         IntentFilter mediaControlFilter = new IntentFilter();
@@ -119,16 +108,12 @@
         mediaControlFilter.addAction(ACTION_PAUSE);
         mediaControlFilter.addAction(ACTION_NEXT);
         mediaControlFilter.addAction(ACTION_PREV);
-        broadcastDispatcher.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
+        mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter,
+                UserHandle.USER_ALL);
 
         createMediaActions();
         mMediaSessionManager =
                 (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
-
-        // The media session listener needs to be re-registered when switching users
-        UserInfoController userInfoController = Dependency.get(UserInfoController.class);
-        userInfoController.addCallback((String name, Drawable picture, String userAccount) ->
-                registerSessionListenerForCurrentUser());
     }
 
     /**
@@ -220,7 +205,7 @@
     /**
      * Re-registers the session listener for the current user.
      */
-    private void registerSessionListenerForCurrentUser() {
+    public void registerSessionListenerForCurrentUser() {
         mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionsChangedListener);
         mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionsChangedListener, null,
                 UserHandle.USER_CURRENT, null);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 5b07db6..4c86ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -34,7 +34,6 @@
 
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.pip.phone.PipMediaController.ActionListener;
-import com.android.systemui.shared.system.InputConsumerController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -86,7 +85,6 @@
     private Context mContext;
     private PipTaskOrganizer mPipTaskOrganizer;
     private PipMediaController mMediaController;
-    private InputConsumerController mInputConsumerController;
 
     private ArrayList<Listener> mListeners = new ArrayList<>();
     private ParceledListSlice<RemoteAction> mAppActions;
@@ -104,12 +102,9 @@
     };
 
     public PipMenuActivityController(Context context,
-            PipMediaController mediaController, InputConsumerController inputConsumerController,
-            PipTaskOrganizer pipTaskOrganizer
-    ) {
+            PipMediaController mediaController, PipTaskOrganizer pipTaskOrganizer) {
         mContext = context;
         mMediaController = mediaController;
-        mInputConsumerController = inputConsumerController;
         mPipTaskOrganizer = pipTaskOrganizer;
     }
 
@@ -119,12 +114,10 @@
 
     public void onActivityPinned() {
         attachPipMenuView();
-        mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
     }
 
     public void onActivityUnpinned() {
         hideMenu();
-        mInputConsumerController.unregisterInputConsumer();
         mPipTaskOrganizer.detachPipMenuViewHost();
         mPipMenuView = null;
     }
@@ -254,7 +247,9 @@
         if (isMenuVisible()) {
             // If the menu is visible in either the closed or full state, then hide the menu and
             // trigger the animation trigger afterwards
-            onStartCallback.run();
+            if (onStartCallback != null) {
+                onStartCallback.run();
+            }
             mPipMenuView.hideMenu(onEndCallback);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
index c66f442..1c38ab3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
@@ -316,7 +316,7 @@
     }
 
     void hideMenu(Runnable animationEndCallback) {
-        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false);
+        hideMenu(animationEndCallback, true /* notifyMenuVisibility */, true /* animate */);
     }
 
     private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
@@ -394,8 +394,10 @@
 
                     // TODO: Check if the action drawable has changed before we reload it
                     action.getIcon().loadDrawableAsync(mContext, d -> {
-                        d.setTint(Color.WHITE);
-                        actionView.setImageDrawable(d);
+                        if (d != null) {
+                            d.setTint(Color.WHITE);
+                            actionView.setImageDrawable(d);
+                        }
                     }, mHandler);
                     actionView.setContentDescription(action.getContentDescription());
                     if (action.isEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 08d9b2a..1e3d871 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -21,13 +21,6 @@
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
 import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -50,11 +43,9 @@
 import android.view.ViewConfiguration;
 
 import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.util.DeviceConfigProxy;
 import com.android.wm.shell.R;
 
 import java.io.PrintWriter;
@@ -71,21 +62,11 @@
     private static final float PINCH_THRESHOLD = 0.05f;
     private static final float STARTING_SCALE_FACTOR = 1.0f;
 
-    private static final int INVALID_SYSUI_STATE_MASK =
-            SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
-            | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
-            | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
-            | SYSUI_STATE_BOUNCER_SHOWING
-            | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
-            | SYSUI_STATE_BUBBLES_EXPANDED
-            | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
-
     private final Context mContext;
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipMotionHelper mMotionHelper;
     private final int mDisplayId;
     private final Executor mMainExecutor;
-    private final SysUiState mSysUiState;
     private final ScaleGestureDetector mScaleGestureDetector;
     private final Region mTmpRegion = new Region();
 
@@ -110,6 +91,7 @@
     private boolean mIsAttached;
     private boolean mIsEnabled;
     private boolean mEnablePinchResize;
+    private boolean mIsSysUiStateValid;
     private boolean mThresholdCrossed;
     private boolean mUsingPinchToZoom = false;
     private float mScaleFactor = STARTING_SCALE_FACTOR;
@@ -123,9 +105,8 @@
     private int mCtrlType;
 
     public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
-            PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
-            PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
-            Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
+            PipMotionHelper motionHelper, PipTaskOrganizer pipTaskOrganizer,
+            Function<Rect, Rect> movementBoundsSupplier, Runnable updateMovementBoundsRunnable,
             PipUiEventLogger pipUiEventLogger, PipMenuActivityController menuActivityController) {
         mContext = context;
         mDisplayId = context.getDisplayId();
@@ -135,7 +116,6 @@
         mPipTaskOrganizer = pipTaskOrganizer;
         mMovementBoundsSupplier = movementBoundsSupplier;
         mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
-        mSysUiState = sysUiState;
         mPipMenuActivityController = menuActivityController;
         mPipUiEventLogger = pipUiEventLogger;
 
@@ -202,7 +182,7 @@
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_PINCH_RESIZE,
                 /* defaultValue = */ false);
-        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
                 new DeviceConfig.OnPropertiesChangedListener() {
                     @Override
                     public void onPropertiesChanged(DeviceConfig.Properties properties) {
@@ -218,6 +198,15 @@
         reloadResources();
     }
 
+    /**
+     * Called when SysUI state changed.
+     *
+     * @param isSysUiStateValid Is SysUI valid or not.
+     */
+    public void onSystemUiStateChanged(boolean isSysUiStateValid) {
+        mIsSysUiStateValid = isSysUiStateValid;
+    }
+
     private void reloadResources() {
         final Resources res = mContext.getResources();
         mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
@@ -319,6 +308,10 @@
         return mTmpRegion.contains(x, y);
     }
 
+    public boolean isUsingPinchToZoom() {
+        return mEnablePinchResize;
+    }
+
     public boolean willStartResizeGesture(MotionEvent ev) {
         if (isInValidSysUiState()) {
             switch (ev.getActionMasked()) {
@@ -401,7 +394,7 @@
     }
 
     private boolean isInValidSysUiState() {
-        return (mSysUiState.getFlags() & INVALID_SYSUI_STATE_MASK) == 0;
+        return mIsSysUiStateValid;
     }
 
     private void onDragCornerResize(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 858683c..1f9125da 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -23,7 +23,6 @@
 import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
 
 import android.annotation.SuppressLint;
-import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -57,13 +56,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipAnimationController;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DismissCircleView;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.util.animation.PhysicsAnimator;
@@ -92,7 +88,6 @@
     private final boolean mEnableResize;
     private final Context mContext;
     private final WindowManager mWindowManager;
-    private final IActivityManager mActivityManager;
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipUiEventLogger mPipUiEventLogger;
 
@@ -216,18 +211,14 @@
     }
 
     @SuppressLint("InflateParams")
-    public PipTouchHandler(Context context, IActivityManager activityManager,
+    public PipTouchHandler(Context context,
             PipMenuActivityController menuController,
-            InputConsumerController inputConsumerController,
             PipBoundsHandler pipBoundsHandler,
             PipTaskOrganizer pipTaskOrganizer,
             FloatingContentCoordinator floatingContentCoordinator,
-            DeviceConfigProxy deviceConfig,
-            SysUiState sysUiState,
             PipUiEventLogger pipUiEventLogger) {
         // Initialize the Pip input consumer
         mContext = context;
-        mActivityManager = activityManager;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mPipBoundsHandler = pipBoundsHandler;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -238,22 +229,18 @@
                 mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
         mPipResizeGestureHandler =
                 new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
-                        deviceConfig, pipTaskOrganizer, this::getMovementBounds,
-                        this::updateMovementBounds, sysUiState, pipUiEventLogger, menuController);
+                        pipTaskOrganizer, this::getMovementBounds,
+                        this::updateMovementBounds, pipUiEventLogger, menuController);
         mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
                 () -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
                         true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
-                        menuController::hideMenu);
+                menuController::hideMenu);
 
         Resources res = context.getResources();
         mEnableDismissDragToEdge = res.getBoolean(R.bool.config_pipEnableDismissDragToEdge);
         mEnableResize = res.getBoolean(R.bool.config_pipEnableResizeForMenu);
         reloadResources();
 
-        // Register the listener for input consumer touch events
-        inputConsumerController.setInputListener(this::handleTouchEvent);
-        inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
-
         mFloatingContentCoordinator = floatingContentCoordinator;
         mConnection = new PipAccessibilityInteractionConnection(mContext, mMotionHelper,
                 pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
@@ -320,15 +307,12 @@
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_STASHING,
                 /* defaultValue = */ false);
-        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                 context.getMainExecutor(),
-                new DeviceConfig.OnPropertiesChangedListener() {
-                    @Override
-                    public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                        if (properties.getKeyset().contains(PIP_STASHING)) {
-                            mEnableStash = properties.getBoolean(
-                                    PIP_STASHING, /* defaultValue = */ false);
-                        }
+                properties -> {
+                    if (properties.getKeyset().contains(PIP_STASHING)) {
+                        mEnableStash = properties.getBoolean(
+                                PIP_STASHING, /* defaultValue = */ false);
                     }
                 });
     }
@@ -438,6 +422,15 @@
         mShelfHeight = shelfHeight;
     }
 
+    /**
+     * Called when SysUI state changed.
+     *
+     * @param isSysUiStateValid Is SysUI valid or not.
+     */
+    public void onSystemUiStateChanged(boolean isSysUiStateValid) {
+        mPipResizeGestureHandler.onSystemUiStateChanged(isSysUiStateValid);
+    }
+
     public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) {
         final Rect toMovementBounds = new Rect();
         mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
@@ -648,7 +641,10 @@
         }
     }
 
-    private void onRegistrationChanged(boolean isRegistered) {
+    /**
+     * TODO Add appropriate description
+     */
+    public void onRegistrationChanged(boolean isRegistered) {
         mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
                 ? mConnection : null);
         if (!isRegistered && mTouchState.isUserInteracting()) {
@@ -664,7 +660,10 @@
                 shouldShowResizeHandle());
     }
 
-    private boolean handleTouchEvent(InputEvent inputEvent) {
+    /**
+     * TODO Add appropriate description
+     */
+    public boolean handleTouchEvent(InputEvent inputEvent) {
         // Skip any non motion events
         if (!(inputEvent instanceof MotionEvent)) {
             return true;
@@ -832,9 +831,7 @@
             // we store back to this snap fraction.  Otherwise, we'll reset the snap
             // fraction and snap to the closest edge.
             if (resize) {
-                Rect expandedBounds = new Rect(mExpandedBounds);
-                mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
-                        mMovementBounds, mExpandedMovementBounds, callback);
+                animateToExpandedState(callback);
             }
         } else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
             // Try and restore the PiP to the closest edge, using the saved snap fraction
@@ -860,13 +857,7 @@
                 }
 
                 if (mDeferResizeToNormalBoundsUntilRotation == -1) {
-                    Rect restoreBounds = new Rect(getUserResizeBounds());
-                    Rect restoredMovementBounds = new Rect();
-                    mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds,
-                            mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
-                    mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
-                            restoredMovementBounds, mMovementBounds, false /* immediate */);
-                    mSavedSnapFraction = -1f;
+                    animateToUnexpandedState(getUserResizeBounds());
                 }
             } else {
                 mSavedSnapFraction = -1f;
@@ -884,6 +875,21 @@
         }
     }
 
+    private void animateToExpandedState(Runnable callback) {
+        Rect expandedBounds = new Rect(mExpandedBounds);
+        mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
+                mMovementBounds, mExpandedMovementBounds, callback);
+    }
+
+    private void animateToUnexpandedState(Rect restoreBounds) {
+        Rect restoredMovementBounds = new Rect();
+        mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds,
+                mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
+        mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
+                restoredMovementBounds, mMovementBounds, false /* immediate */);
+        mSavedSnapFraction = -1f;
+    }
+
     /**
      * @return the motion helper.
      */
@@ -1026,10 +1032,24 @@
                             this::flingEndAction /* endAction */);
                 }
             } else if (mTouchState.isDoubleTap()) {
-                // Expand to fullscreen if this is a double tap
-                // the PiP should be frozen until the transition ends
-                setTouchEnabled(false);
-                mMotionHelper.expandLeavePip();
+                // If using pinch to zoom, double-tap functions as resizing between max/min size
+                if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
+                    final boolean toExpand =
+                            mMotionHelper.getBounds().width() < mExpandedBounds.width()
+                            && mMotionHelper.getBounds().height() < mExpandedBounds.height();
+                    mPipResizeGestureHandler.setUserResizeBounds(toExpand ? mExpandedBounds
+                            : mNormalBounds);
+                    if (toExpand) {
+                        animateToExpandedState(null);
+                    } else {
+                        animateToUnexpandedState(mNormalBounds);
+                    }
+                } else {
+                    // Expand to fullscreen if this is a double tap
+                    // the PiP should be frozen until the transition ends
+                    setTouchEnabled(false);
+                    mMotionHelper.expandLeavePip();
+                }
             } else if (mMenuState != MENU_STATE_FULL) {
                 if (!mTouchState.isWaitingForDoubleTap()) {
                     // User has stalled long enough for this not to be a drag or a double tap, just
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index 12a545a..6ac4e4cb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -20,7 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
-import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityTaskManager;
@@ -45,23 +45,16 @@
 import android.util.Log;
 import android.view.DisplayInfo;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.UiOffloadThread;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.shared.system.PinnedStackListenerForwarder;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * Manages the picture-in-picture (PIP) UI and states.
@@ -113,7 +106,6 @@
     private Context mContext;
     private PipBoundsHandler mPipBoundsHandler;
     private PipTaskOrganizer mPipTaskOrganizer;
-    private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
     private IActivityTaskManager mActivityTaskManager;
     private MediaSessionManager mMediaSessionManager;
     private int mState = STATE_NO_PIP;
@@ -133,6 +125,7 @@
     private String[] mLastPackagesResourceGranted;
     private PipNotification mPipNotification;
     private ParceledListSlice<RemoteAction> mCustomActions;
+    private WindowManagerShellWrapper mWindowManagerShellWrapper;
     private int mResizeAnimationDuration;
 
     // Used to calculate the movement bounds
@@ -143,21 +136,9 @@
     private boolean mImeVisible;
     private int mImeHeightAdjustment;
 
-    private final PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener();
-
-    private final Runnable mResizePinnedStackRunnable = new Runnable() {
-        @Override
-        public void run() {
-            resizePinnedStack(mResumeResizePinnedStackRunnableState);
-        }
-    };
-    private final Runnable mClosePipRunnable = new Runnable() {
-        @Override
-        public void run() {
-            closePip();
-        }
-    };
-
+    private final Runnable mResizePinnedStackRunnable =
+            () -> resizePinnedStack(mResumeResizePinnedStackRunnableState);
+    private final Runnable mClosePipRunnable = () -> closePip();
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -175,17 +156,23 @@
         }
     };
     private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener =
-            new MediaSessionManager.OnActiveSessionsChangedListener() {
-                @Override
-                public void onActiveSessionsChanged(List<MediaController> controllers) {
-                    updateMediaController(controllers);
-                }
-            };
+            controllers -> updateMediaController(controllers);
+    private final PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
+            new PipControllerPinnedStackListener();
+
+    @Override
+    public void registerSessionListenerForCurrentUser() {
+        // TODO Need confirm if TV have to re-registers when switch user
+        mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener);
+        mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveMediaSessionListener, null,
+                UserHandle.USER_CURRENT, null);
+    }
 
     /**
      * Handler for messages from the PIP controller.
      */
-    private class PipControllerPinnedStackListener extends PinnedStackListener {
+    private class PipControllerPinnedStackListener extends
+            PinnedStackListenerForwarder.PinnedStackListener {
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mHandler.post(() -> {
@@ -227,18 +214,18 @@
         }
     }
 
-    public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
+    public PipController(Context context,
             PipBoundsHandler pipBoundsHandler,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
-            PipTaskOrganizer pipTaskOrganizer) {
+            PipTaskOrganizer pipTaskOrganizer,
+            WindowManagerShellWrapper windowManagerShellWrapper
+    ) {
         if (mInitialized) {
             return;
         }
 
         mInitialized = true;
         mContext = context;
-        mPipNotification = new PipNotification(context, broadcastDispatcher,
-                Optional.of(this).get());
+        mPipNotification = new PipNotification(context, this);
         mPipBoundsHandler = pipBoundsHandler;
         // Ensure that we have the display info in case we get calls to update the bounds before the
         // listener calls back
@@ -248,15 +235,12 @@
 
         mResizeAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipResizeAnimationDuration);
-        mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
         mPipTaskOrganizer = pipTaskOrganizer;
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mActivityTaskManager = ActivityTaskManager.getService();
-        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
-        broadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter,
-                null /* handler */, UserHandle.ALL);
+        mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL);
 
         // Initialize the last orientation and apply the current configuration
         Configuration initialConfig = mContext.getResources().getConfiguration();
@@ -265,10 +249,10 @@
 
         mMediaSessionManager =
                 (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
-
+        mWindowManagerShellWrapper = windowManagerShellWrapper;
         try {
-            WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener);
-        } catch (RemoteException | UnsupportedOperationException e) {
+            mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
+        } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
     }
@@ -344,7 +328,6 @@
             mListeners.get(i).onPipActivityClosed();
         }
         mHandler.removeCallbacks(mClosePipRunnable);
-        updatePipVisibility(false);
     }
 
     /**
@@ -358,7 +341,77 @@
             mListeners.get(i).onMoveToFullscreen();
         }
         resizePinnedStack(STATE_NO_PIP);
-        updatePipVisibility(false);
+    }
+
+    @Override
+    public void onActivityPinned(String packageName) {
+        if (DEBUG) Log.d(TAG, "onActivityPinned()");
+
+        RootTaskInfo taskInfo = getPinnedTaskInfo();
+        if (taskInfo == null) {
+            Log.w(TAG, "Cannot find pinned stack");
+            return;
+        }
+        if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo);
+        mPinnedStackId = taskInfo.taskId;
+        mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
+        mPipComponentName = ComponentName.unflattenFromString(
+                taskInfo.childTaskNames[taskInfo.childTaskNames.length - 1]);
+        // Set state to STATE_PIP so we show it when the pinned stack animation ends.
+        mState = STATE_PIP;
+        mMediaSessionManager.addOnActiveSessionsChangedListener(
+                mActiveMediaSessionListener, null);
+        updateMediaController(mMediaSessionManager.getActiveSessions(null));
+        for (int i = mListeners.size() - 1; i >= 0; i--) {
+            mListeners.get(i).onPipEntered(packageName);
+        }
+    }
+
+    @Override
+    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+            boolean clearedTask) {
+        if (task.configuration.windowConfiguration.getWindowingMode()
+                != WINDOWING_MODE_PINNED) {
+            return;
+        }
+        if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
+
+        // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
+        movePipToFullscreen();
+    }
+
+    @Override
+    public void onTaskStackChanged() {
+        if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
+
+        if (getState() != STATE_NO_PIP) {
+            boolean hasPip = false;
+
+            RootTaskInfo taskInfo = getPinnedTaskInfo();
+            if (taskInfo == null || taskInfo.childTaskIds == null) {
+                Log.w(TAG, "There is nothing in pinned stack");
+                closePipInternal(false);
+                return;
+            }
+            for (int i = taskInfo.childTaskIds.length - 1; i >= 0; --i) {
+                if (taskInfo.childTaskIds[i] == mPipTaskId) {
+                    // PIP task is still alive.
+                    hasPip = true;
+                    break;
+                }
+            }
+            if (!hasPip) {
+                // PIP task doesn't exist anymore in PINNED_STACK.
+                closePipInternal(true);
+                return;
+            }
+        }
+        if (getState() == STATE_PIP) {
+            if (mPipBounds != mDefaultPipBounds) {
+                mPipBounds = mDefaultPipBounds;
+                resizePinnedStack(STATE_PIP);
+            }
+        }
     }
 
     /**
@@ -603,80 +656,6 @@
         return PLAYBACK_STATE_UNAVAILABLE;
     }
 
-    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-        @Override
-        public void onTaskStackChanged() {
-            if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
-
-            if (getState() != STATE_NO_PIP) {
-                boolean hasPip = false;
-
-                RootTaskInfo taskInfo = getPinnedTaskInfo();
-                if (taskInfo == null || taskInfo.childTaskIds == null) {
-                    Log.w(TAG, "There is nothing in pinned stack");
-                    closePipInternal(false);
-                    return;
-                }
-                for (int i = taskInfo.childTaskIds.length - 1; i >= 0; --i) {
-                    if (taskInfo.childTaskIds[i] == mPipTaskId) {
-                        // PIP task is still alive.
-                        hasPip = true;
-                        break;
-                    }
-                }
-                if (!hasPip) {
-                    // PIP task doesn't exist anymore in PINNED_STACK.
-                    closePipInternal(true);
-                    return;
-                }
-            }
-            if (getState() == STATE_PIP) {
-                if (mPipBounds != mDefaultPipBounds) {
-                    mPipBounds = mDefaultPipBounds;
-                    resizePinnedStack(STATE_PIP);
-                }
-            }
-        }
-
-        @Override
-        public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
-            if (DEBUG) Log.d(TAG, "onActivityPinned()");
-
-            RootTaskInfo taskInfo = getPinnedTaskInfo();
-            if (taskInfo == null) {
-                Log.w(TAG, "Cannot find pinned stack");
-                return;
-            }
-            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo);
-            mPinnedStackId = taskInfo.taskId;
-            mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
-            mPipComponentName = ComponentName.unflattenFromString(
-                    taskInfo.childTaskNames[taskInfo.childTaskNames.length - 1]);
-            // Set state to STATE_PIP so we show it when the pinned stack animation ends.
-            mState = STATE_PIP;
-            mMediaSessionManager.addOnActiveSessionsChangedListener(
-                    mActiveMediaSessionListener, null);
-            updateMediaController(mMediaSessionManager.getActiveSessions(null));
-            for (int i = mListeners.size() - 1; i >= 0; i--) {
-                mListeners.get(i).onPipEntered(packageName);
-            }
-            updatePipVisibility(true);
-        }
-
-        @Override
-        public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
-                boolean clearedTask, boolean wasVisible) {
-            if (task.configuration.windowConfiguration.getWindowingMode()
-                    != WINDOWING_MODE_PINNED) {
-                return;
-            }
-            if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
-
-            // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
-            movePipToFullscreen();
-        }
-    };
-
     @Override
     public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
     }
@@ -730,12 +709,6 @@
         void onMediaControllerChanged();
     }
 
-    private void updatePipVisibility(final boolean visible) {
-        Dependency.get(UiOffloadThread.class).execute(() -> {
-            WindowManagerWrapper.getInstance().setPipVisibility(visible);
-        });
-    }
-
     private String getStateDescription() {
         if (mSuspendPipResizingReason == 0) {
             return stateToName(mState);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
index 2f4df1f..8c04a52 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
@@ -147,9 +147,10 @@
                 return;
             }
             mPipOptional.ifPresent(pip -> {
-                if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PAUSED) {
+                final int playbackState = pip.getPlaybackState();
+                if (playbackState == PipController.PLAYBACK_STATE_PAUSED) {
                     mMediaController.getTransportControls().play();
-                } else if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PLAYING) {
+                } else if (playbackState == PipController.PLAYBACK_STATE_PLAYING) {
                     mMediaController.getTransportControls().pause();
                 }
             });
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 78569ed..0666811 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -32,11 +32,11 @@
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.util.NotificationChannels;
 import com.android.wm.shell.R;
 
@@ -163,8 +163,7 @@
         }
     };
 
-    public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher,
-            PipController pipController) {
+    public PipNotification(Context context, PipController pipController) {
         mPackageManager = context.getPackageManager();
 
         mNotificationManager = (NotificationManager) context.getSystemService(
@@ -185,7 +184,7 @@
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ACTION_MENU);
         intentFilter.addAction(ACTION_CLOSE);
-        broadcastDispatcher.registerReceiver(mEventReceiver, intentFilter);
+        context.registerReceiver(mEventReceiver, intentFilter, UserHandle.USER_ALL);
 
         onConfigurationChanged(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java
index e8e3920..f094854 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipModule.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.content.Context;
 
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.PipBoundsHandler;
@@ -29,6 +28,7 @@
 import com.android.systemui.pip.tv.PipController;
 import com.android.systemui.pip.tv.PipMenuActivity;
 import com.android.systemui.pip.tv.PipNotification;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.splitscreen.SplitScreen;
@@ -56,20 +56,18 @@
     @SysUISingleton
     @Provides
     static Pip providePipController(Context context,
-            BroadcastDispatcher broadcastDispatcher,
             PipBoundsHandler pipBoundsHandler,
-            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
-            PipTaskOrganizer pipTaskOrganizer) {
-        return new PipController(context, broadcastDispatcher, pipBoundsHandler,
-                pipSurfaceTransactionHelper, pipTaskOrganizer);
+            PipTaskOrganizer pipTaskOrganizer,
+            WindowManagerShellWrapper windowManagerShellWrapper) {
+        return new PipController(context, pipBoundsHandler, pipTaskOrganizer,
+                windowManagerShellWrapper);
     }
 
     @SysUISingleton
     @Provides
     static PipNotification providePipNotification(Context context,
-            BroadcastDispatcher broadcastDispatcher,
             PipController pipController) {
-        return new PipNotification(context, broadcastDispatcher, pipController);
+        return new PipNotification(context, pipController);
     }
 
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ed8da7c..aa43516 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -102,6 +102,7 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -142,6 +143,7 @@
 
     private Region mActiveNavBarRegion;
 
+    private IPinnedStackAnimationListener mIPinnedStackAnimationListener;
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private boolean mBound;
@@ -158,7 +160,6 @@
 
     @VisibleForTesting
     public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
-
         @Override
         public void startScreenPinning(int taskId) {
             if (!verifyCaller("startScreenPinning")) {
@@ -438,10 +439,11 @@
                         + mHasPipFeature);
                 return;
             }
+            mIPinnedStackAnimationListener = listener;
             long token = Binder.clearCallingIdentity();
             try {
                 mPipOptional.ifPresent(
-                        pip -> pip.setPinnedStackAnimationListener(listener));
+                        pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback));
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -607,6 +609,8 @@
     private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
     private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
             this::notifySplitScreenBoundsChanged;
+    private final Consumer<Boolean> mPinnedStackAnimationCallback =
+            this::notifyPinnedStackAnimationStarted;
 
     // This is the death handler for the binder from the launcher service
     private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
@@ -736,6 +740,17 @@
         }
     }
 
+    private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) {
+        if (mIPinnedStackAnimationListener == null) {
+            return;
+        }
+        try {
+            mIPinnedStackAnimationListener.onPinnedStackAnimationStarted();
+        } catch (RemoteException e) {
+            Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e);
+        }
+    }
+
     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
             boolean bouncerShowing) {
         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
@@ -766,7 +781,7 @@
 
     public void cleanupAfterDeath() {
         if (mInputFocusTransferStarted) {
-            mHandler.post(()-> {
+            mHandler.post(() -> {
                 mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
                     mInputFocusTransferStarted = false;
                     statusBarLazy.get().onInputFocusTransfer(false, true /* cancel */,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index c1196d6..01aa53f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -189,7 +189,11 @@
         blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
         val zoomOut = blurUtils.ratioOfBlurRadius(blur)
         try {
-            wallpaperManager.setWallpaperZoomOut(root.windowToken, zoomOut)
+            if (root.isAttachedToWindow) {
+                wallpaperManager.setWallpaperZoomOut(root.windowToken, zoomOut)
+            } else {
+                Log.i(TAG, "Won't set zoom. Window not attached $root")
+            }
         } catch (e: IllegalArgumentException) {
             Log.w(TAG, "Can't set zoom. Window is gone: ${root.windowToken}", e)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index c43ad36..82ad00a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -359,6 +360,11 @@
         return false;
     }
 
+    private static boolean isOngoingCallNotif(NotificationEntry entry) {
+        return entry.getSbn().isOngoing() && Notification.CATEGORY_CALL.equals(
+                entry.getSbn().getNotification().category);
+    }
+
     /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created.
@@ -391,6 +397,15 @@
                 return 1;
             }
 
+            boolean selfCall = isOngoingCallNotif(mEntry);
+            boolean otherCall = isOngoingCallNotif(headsUpEntry.mEntry);
+
+            if (selfCall && !otherCall) {
+                return -1;
+            } else if (!selfCall && otherCall) {
+                return 1;
+            }
+
             if (remoteInputActive && !headsUpEntry.remoteInputActive) {
                 return -1;
             } else if (!remoteInputActive && headsUpEntry.remoteInputActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index a29db4d..7aeca64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -21,7 +21,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
 import android.annotation.UiThread;
@@ -36,7 +35,6 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
-import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.tv.TvStatusBar;
@@ -83,19 +81,14 @@
     private static final int STATE_SHOWN = 2;
     private static final int STATE_DISAPPEARING = 3;
 
-    private static final int ANIMATION_DURATION = 600;
+    private static final int ANIMATION_DURATION_MS = 200;
 
     private final Context mContext;
     private boolean mIsEnabled;
 
     private View mIndicatorView;
-    private View mIconTextsContainer;
-    private View mIconContainerBg;
-    private View mIcon;
-    private View mBgEnd;
-    private View mTextsContainers;
-    private TextView mTextView;
-    private boolean mIsLtr;
+    private boolean mViewAndWindowAdded;
+    private ObjectAnimator mAnimator;
 
     @State private int mState = STATE_STOPPED;
 
@@ -190,7 +183,7 @@
         }
 
         if (active) {
-            showIfNotShown();
+            showIfNeeded();
         } else {
             hideIndicatorIfNeeded();
         }
@@ -198,153 +191,132 @@
 
     @UiThread
     private void hideIndicatorIfNeeded() {
-        // If not STATE_APPEARING, will check whether the indicator should be hidden when the
-        // indicator comes to the STATE_SHOWN.
-        // If STATE_DISAPPEARING or STATE_SHOWN - nothing else for us to do here.
-        if (mState != STATE_SHOWN) return;
+        // If STOPPED, NOT_SHOWN or DISAPPEARING - nothing else for us to do here.
+        if (mState != STATE_SHOWN && mState != STATE_APPEARING) return;
 
-        // If is in the STATE_SHOWN and there are no active recorders - hide.
-        if (!hasActiveRecorders()) {
-            hide();
+        if (hasActiveRecorders()) {
+            return;
+        }
+
+        if (mViewAndWindowAdded) {
+            mState = STATE_DISAPPEARING;
+            animateDisappearance();
+        } else {
+            // Appearing animation has not started yet, as we were still waiting for the View to be
+            // laid out.
+            mState = STATE_NOT_SHOWN;
+            removeIndicatorView();
         }
     }
 
     @UiThread
-    private void showIfNotShown() {
-        if (mState != STATE_NOT_SHOWN) return;
+    private void showIfNeeded() {
+        // If STOPPED, SHOWN or APPEARING - nothing else for us to do here.
+        if (mState != STATE_NOT_SHOWN && mState != STATE_DISAPPEARING) return;
+
         if (DEBUG) Log.d(TAG, "Showing indicator");
 
-        mIsLtr = mContext.getResources().getConfiguration().getLayoutDirection()
-                == View.LAYOUT_DIRECTION_LTR;
+        final int prevState = mState;
+        mState = STATE_APPEARING;
+
+        if (prevState == STATE_DISAPPEARING) {
+            animateAppearance();
+            return;
+        }
 
         // Inflate the indicator view
         mIndicatorView = LayoutInflater.from(mContext).inflate(
-                R.layout.tv_audio_recording_indicator,
-                null);
-        mIconTextsContainer = mIndicatorView.findViewById(R.id.icon_texts_container);
-        mIconContainerBg = mIconTextsContainer.findViewById(R.id.icon_container_bg);
-        mIcon = mIconTextsContainer.findViewById(R.id.icon_mic);
-        mTextsContainers = mIconTextsContainer.findViewById(R.id.texts_container);
-        mTextView = mTextsContainers.findViewById(R.id.text);
-        mBgEnd = mIndicatorView.findViewById(R.id.bg_end);
+                R.layout.tv_audio_recording_indicator, null);
 
-        mTextsContainers.setVisibility(View.GONE);
-        mIconContainerBg.setVisibility(View.GONE);
-        mTextView.setVisibility(View.GONE);
-        mBgEnd.setVisibility(View.GONE);
-        mTextsContainers = null;
-        mIconContainerBg = null;
-        mTextView = null;
-        mBgEnd = null;
-
-        // Initially change the visibility to INVISIBLE, wait until and receives the size and
-        // then animate it moving from "off" the screen correctly
-        mIndicatorView.setVisibility(View.INVISIBLE);
+        // 1. Set alpha to 0.
+        // 2. Wait until the window is shown and the view is laid out.
+        // 3. Start a "fade in" (alpha) animation.
+        mIndicatorView.setAlpha(0f);
         mIndicatorView
                 .getViewTreeObserver()
                 .addOnGlobalLayoutListener(
                         new ViewTreeObserver.OnGlobalLayoutListener() {
                             @Override
                             public void onGlobalLayout() {
-                                if (mState == STATE_STOPPED) {
-                                    return;
-                                }
+                                // State could have changed to NOT_SHOWN (if all the recorders are
+                                // already gone) to STOPPED (if the indicator was disabled)
+                                if (mState != STATE_APPEARING) return;
 
+                                mViewAndWindowAdded = true;
                                 // Remove the observer
                                 mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener(
                                         this);
 
-                                // Now that the width of the indicator has been assigned, we can
-                                // move it in from off the screen.
-                                final int initialOffset =
-                                        (mIsLtr ? 1 : -1) * mIndicatorView.getWidth();
-                                final AnimatorSet set = new AnimatorSet();
-                                set.setDuration(ANIMATION_DURATION);
-                                set.playTogether(
-                                        ObjectAnimator.ofFloat(mIndicatorView,
-                                                View.TRANSLATION_X, initialOffset, 0),
-                                        ObjectAnimator.ofFloat(mIndicatorView, View.ALPHA, 0f,
-                                                1f));
-                                set.addListener(
-                                        new AnimatorListenerAdapter() {
-                                            @Override
-                                            public void onAnimationStart(Animator animation,
-                                                    boolean isReverse) {
-                                                if (mState == STATE_STOPPED) return;
-
-                                                // Indicator is INVISIBLE at the moment, change it.
-                                                mIndicatorView.setVisibility(View.VISIBLE);
-                                            }
-
-                                            @Override
-                                            public void onAnimationEnd(Animator animation) {
-                                                onAppeared();
-                                            }
-                                        });
-                                set.start();
+                                animateAppearance();
                             }
                         });
 
+        final boolean isLtr = mContext.getResources().getConfiguration().getLayoutDirection()
+                == View.LAYOUT_DIRECTION_LTR;
         final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                 WRAP_CONTENT,
                 WRAP_CONTENT,
                 WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                 PixelFormat.TRANSLUCENT);
-        layoutParams.gravity = Gravity.TOP | (mIsLtr ? Gravity.RIGHT : Gravity.LEFT);
+        layoutParams.gravity = Gravity.TOP | (isLtr ? Gravity.RIGHT : Gravity.LEFT);
         layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
         layoutParams.packageName = mContext.getPackageName();
         final WindowManager windowManager = (WindowManager) mContext.getSystemService(
                 Context.WINDOW_SERVICE);
         windowManager.addView(mIndicatorView, layoutParams);
-
-        mState = STATE_APPEARING;
     }
 
-    @UiThread
-    private void hide() {
-        if (DEBUG) Log.d(TAG, "Hide indicator");
 
-        final int targetOffset = (mIsLtr ? 1 : -1) * (mIndicatorView.getWidth()
-                - (int) mIconTextsContainer.getTranslationX());
-        final AnimatorSet set = new AnimatorSet();
-        set.playTogether(
-                ObjectAnimator.ofFloat(mIndicatorView, View.TRANSLATION_X, targetOffset),
-                ObjectAnimator.ofFloat(mIcon, View.ALPHA, 0f));
-        set.setDuration(ANIMATION_DURATION);
-        set.addListener(
-                new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        onHidden();
+    private void animateAppearance() {
+        animateAlphaTo(1f);
+    }
+
+    private void animateDisappearance() {
+        animateAlphaTo(0f);
+    }
+
+    private void animateAlphaTo(final float endValue) {
+        if (mAnimator == null) {
+            if (DEBUG) Log.d(TAG, "set up animator");
+
+            mAnimator = new ObjectAnimator();
+            mAnimator.setTarget(mIndicatorView);
+            mAnimator.setProperty(View.ALPHA);
+            mAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation, boolean isReverse) {
+                    if (DEBUG) Log.d(TAG, "onAnimationStart");
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    if (DEBUG) Log.d(TAG, "onAnimationCancel");
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (DEBUG) Log.d(TAG, "onAnimationEnd");
+
+                    if (mState == STATE_APPEARING) {
+                        mState = STATE_SHOWN;
+                    } else if (mState == STATE_DISAPPEARING) {
+                        removeIndicatorView();
+                        mState = STATE_NOT_SHOWN;
                     }
-                });
-        set.start();
-
-        mState = STATE_DISAPPEARING;
-    }
-
-
-    @UiThread
-    private void onAppeared() {
-        if (mState == STATE_STOPPED) return;
-
-        mState = STATE_SHOWN;
-
-        hideIndicatorIfNeeded();
-    }
-
-    @UiThread
-    private void onHidden() {
-        if (mState == STATE_STOPPED) return;
-
-        removeIndicatorView();
-        mState = STATE_NOT_SHOWN;
-
-        if (hasActiveRecorders()) {
-            // Got new recorders, show again.
-            showIfNotShown();
+                }
+            });
+        } else if (mAnimator.isRunning()) {
+            if (DEBUG) Log.d(TAG, "cancel running animation");
+            mAnimator.cancel();
         }
+
+        final float currentValue = mIndicatorView.getAlpha();
+        if (DEBUG) Log.d(TAG, "animate alpha to " + endValue + " from " + currentValue);
+
+        mAnimator.setDuration((int) (Math.abs(currentValue - endValue) * ANIMATION_DURATION_MS));
+        mAnimator.setFloatValues(endValue);
+        mAnimator.start();
     }
 
     private boolean hasActiveRecorders() {
@@ -363,12 +335,9 @@
         windowManager.removeView(mIndicatorView);
 
         mIndicatorView = null;
-        mIconTextsContainer = null;
-        mIconContainerBg = null;
-        mIcon = null;
-        mTextsContainers = null;
-        mTextView = null;
-        mBgEnd = null;
+        mAnimator = null;
+
+        mViewAndWindowAdded = false;
     }
 
     private static List<String> splitByComma(String string) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 78f83d3..2081cfe 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -122,8 +122,11 @@
     static final int DIALOG_SAFETYWARNING_TIMEOUT_MILLIS = 5000;
     static final int DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS = 5000;
     static final int DIALOG_HOVERING_TIMEOUT_MILLIS = 16000;
-    static final int DIALOG_SHOW_ANIMATION_DURATION = 300;
-    static final int DIALOG_HIDE_ANIMATION_DURATION = 250;
+
+    private final int mDialogShowAnimationDurationMs;
+    private final int mDialogHideAnimationDurationMs;
+    private final boolean mShowLowMediaVolumeIcon;
+    private final boolean mChangeVolumeRowTintWhenInactive;
 
     private final Context mContext;
     private final H mHandler = new H();
@@ -154,8 +157,6 @@
     private boolean mShowing;
     private boolean mShowA11yStream;
 
-    private final boolean mShowLowMediaVolumeIcon;
-
     private int mActiveStream;
     private int mPrevActiveStream;
     private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
@@ -183,6 +184,12 @@
                 Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
         mShowLowMediaVolumeIcon =
             mContext.getResources().getBoolean(R.bool.config_showLowMediaVolumeIcon);
+        mChangeVolumeRowTintWhenInactive =
+            mContext.getResources().getBoolean(R.bool.config_changeVolumeRowTintWhenInactive);
+        mDialogShowAnimationDurationMs =
+            mContext.getResources().getInteger(R.integer.config_dialogShowAnimationDurationMs);
+        mDialogHideAnimationDurationMs =
+            mContext.getResources().getInteger(R.integer.config_dialogHideAnimationDurationMs);
     }
 
     @Override
@@ -272,7 +279,7 @@
             mDialogView.animate()
                     .alpha(1)
                     .translationX(0)
-                    .setDuration(DIALOG_SHOW_ANIMATION_DURATION)
+                    .setDuration(mDialogShowAnimationDurationMs)
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .withEndAction(() -> {
                         if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
@@ -592,7 +599,7 @@
             mODICaptionsTooltipView.setAlpha(0.f);
             mODICaptionsTooltipView.animate()
                 .alpha(1.f)
-                .setStartDelay(DIALOG_SHOW_ANIMATION_DURATION)
+                .setStartDelay(mDialogShowAnimationDurationMs)
                 .withEndAction(() -> {
                     if (D.BUG) Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
                     Prefs.putBoolean(mContext,
@@ -614,7 +621,7 @@
             mODICaptionsTooltipView.animate()
                     .alpha(0.f)
                     .setStartDelay(0)
-                    .setDuration(DIALOG_HIDE_ANIMATION_DURATION)
+                    .setDuration(mDialogHideAnimationDurationMs)
                     .withEndAction(() -> mODICaptionsTooltipView.setVisibility(INVISIBLE))
                     .start();
         }
@@ -793,7 +800,7 @@
         mDialogView.setAlpha(1);
         ViewPropertyAnimator animator = mDialogView.animate()
                 .alpha(0)
-                .setDuration(DIALOG_HIDE_ANIMATION_DURATION)
+                .setDuration(mDialogHideAnimationDurationMs)
                 .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
                 .withEndAction(() -> mHandler.postDelayed(() -> {
                     mDialog.dismiss();
@@ -1076,7 +1083,7 @@
             iconRes = isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute
                                         : R.drawable.ic_volume_media_bt;
         } else if (isStreamMuted(ss)) {
-            iconRes = row.iconMuteRes;
+            iconRes = ss.muted ? R.drawable.ic_volume_media_off : row.iconMuteRes;
         } else {
             iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin)
                       ? R.drawable.ic_volume_media_low : row.iconRes;
@@ -1154,6 +1161,9 @@
             row.slider.requestFocus();
         }
         boolean useActiveColoring = isActive && row.slider.isEnabled();
+        if (!useActiveColoring && !mChangeVolumeRowTintWhenInactive) {
+            return;
+        }
         final ColorStateList tint = useActiveColoring
                 ? Utils.getColorAccent(mContext)
                 : Utils.getColorAttr(mContext, android.R.attr.colorForeground);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 524eca3..d6595b2 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -49,8 +49,6 @@
         return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
     }
 
-    @SysUISingleton
-    @Provides
     static SplitScreen provideSplitScreen(Context context,
             DisplayController displayController, SystemWindows systemWindows,
             DisplayImeController displayImeController, @Main Handler handler,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a2d6ac8..250c592 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -16,24 +16,40 @@
 
 package com.android.systemui.wmshell;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.keyguard.ScreenLifecycle;
@@ -42,9 +58,12 @@
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.phone.PipUtils;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.tracing.ProtoTraceable;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -70,8 +89,20 @@
 @SysUISingleton
 public final class WMShell extends SystemUI
         implements CommandQueue.Callbacks, ProtoTraceable<SystemUiTraceProto> {
+    private static final String TAG = WMShell.class.getName();
+    private static final int INVALID_SYSUI_STATE_MASK =
+            SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
+                    | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+                    | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
+                    | SYSUI_STATE_BOUNCER_SHOWING
+                    | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+                    | SYSUI_STATE_BUBBLES_EXPANDED
+                    | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+
     private final CommandQueue mCommandQueue;
+    private final ConfigurationController mConfigurationController;
     private final DisplayImeController mDisplayImeController;
+    private final InputConsumerController mInputConsumerController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ActivityManagerWrapper mActivityManagerWrapper;
     private final NavigationModeController mNavigationModeController;
@@ -84,12 +115,15 @@
     // are non-optional windowing features like FULLSCREEN.
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final ProtoTracer mProtoTracer;
-
+    private boolean mIsSysUiStateValid;
     private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
+    private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
     private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
 
     @Inject
     public WMShell(Context context, CommandQueue commandQueue,
+            ConfigurationController configurationController,
+            InputConsumerController inputConsumerController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             ActivityManagerWrapper activityManagerWrapper,
             DisplayImeController displayImeController,
@@ -103,6 +137,8 @@
             ProtoTracer protoTracer) {
         super(context);
         mCommandQueue = commandQueue;
+        mConfigurationController = configurationController;
+        mInputConsumerController = inputConsumerController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mActivityManagerWrapper = activityManagerWrapper;
         mDisplayImeController = displayImeController;
@@ -140,6 +176,90 @@
                 pip.showPictureInPictureMenu();
             }
         });
+
+        mPipKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+            @Override
+            public void onKeyguardVisibilityChanged(boolean showing) {
+                if (showing) {
+                    pip.hidePipMenu(null, null);
+                }
+            }
+        };
+        mKeyguardUpdateMonitor.registerCallback(mPipKeyguardCallback);
+
+        mSysUiState.addCallback(sysUiStateFlag -> {
+            mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
+            pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
+        });
+
+        mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+            @Override
+            public void onDensityOrFontScaleChanged() {
+                pip.onDensityOrFontScaleChanged();
+            }
+
+            @Override
+            public void onOverlayChanged() {
+                pip.onOverlayChanged();
+            }
+        });
+
+        // Handle for system task stack changes.
+        mActivityManagerWrapper.registerTaskStackListener(
+                new TaskStackChangeListener() {
+                    @Override
+                    public void onTaskStackChanged() {
+                        pip.onTaskStackChanged();
+                    }
+
+                    @Override
+                    public void onActivityPinned(String packageName, int userId, int taskId,
+                            int stackId) {
+                        pip.onActivityPinned(packageName);
+                        mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
+                    }
+
+                    @Override
+                    public void onActivityUnpinned() {
+                        final Pair<ComponentName, Integer> topPipActivityInfo =
+                                PipUtils.getTopPipActivity(
+                                        mContext, ActivityManager.getService());
+                        final ComponentName topActivity = topPipActivityInfo.first;
+                        pip.onActivityUnpinned(topActivity);
+                        mInputConsumerController.unregisterInputConsumer();
+                    }
+
+                    @Override
+                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                        pip.onActivityRestartAttempt(task, clearedTask);
+                    }
+                });
+
+        try {
+            RootTaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
+                    WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+            if (taskInfo != null) {
+                // If SystemUI restart, and it already existed a pinned stack,
+                // register the pip input consumer to ensure touch can send to it.
+                mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
+            }
+        } catch (RemoteException | UnsupportedOperationException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
+            e.printStackTrace();
+        }
+
+        // Register the listener for input consumer touch events. Only for Phone
+        if (pip.getPipTouchHandler() != null) {
+            mInputConsumerController.setInputListener(pip.getPipTouchHandler()::handleTouchEvent);
+            mInputConsumerController.setRegistrationListener(
+                    pip.getPipTouchHandler()::onRegistrationChanged);
+        }
+
+        // The media session listener needs to be re-registered when switching users
+        UserInfoController userInfoController = Dependency.get(UserInfoController.class);
+        userInfoController.addCallback((String name, Drawable picture, String userAccount) ->
+                pip.registerSessionListenerForCurrentUser());
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 7c129ac..ae96829 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.wmshell;
 
+import android.app.IActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Handler;
@@ -28,7 +29,10 @@
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.pip.phone.PipAppOpsListener;
+import com.android.systemui.pip.phone.PipMediaController;
+import com.android.systemui.pip.phone.PipTouchHandler;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -71,12 +75,33 @@
 
     @SysUISingleton
     @Provides
+    static InputConsumerController provideInputConsumerController() {
+        return InputConsumerController.getPipInputConsumer();
+    }
+
+    @SysUISingleton
+    @Provides
     static FloatingContentCoordinator provideFloatingContentCoordinator() {
         return new FloatingContentCoordinator();
     }
 
     @SysUISingleton
     @Provides
+    static PipAppOpsListener providesPipAppOpsListener(Context context,
+            IActivityManager activityManager,
+            PipTouchHandler pipTouchHandler) {
+        return new PipAppOpsListener(context, activityManager, pipTouchHandler.getMotionHelper());
+    }
+
+    @SysUISingleton
+    @Provides
+    static PipMediaController providesPipMediaController(Context context,
+            IActivityManager activityManager) {
+        return new PipMediaController(context, activityManager);
+    }
+
+    @SysUISingleton
+    @Provides
     static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
             PackageManager packageManager) {
         return new PipUiEventLogger(uiEventLogger, packageManager);
@@ -84,9 +109,8 @@
 
     @SysUISingleton
     @Provides
-    static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context,
-            ConfigurationController configController) {
-        return new PipSurfaceTransactionHelper(context, configController);
+    static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context) {
+        return new PipSurfaceTransactionHelper(context);
     }
 
     @SysUISingleton
@@ -106,6 +130,12 @@
 
     @SysUISingleton
     @Provides
+    static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
+        return new WindowManagerShellWrapper();
+    }
+
+    @SysUISingleton
+    @Provides
     static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder(
             DisplayMetrics displayMetrics) {
         return new FlingAnimationUtils.Builder(displayMetrics);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 16fb2ca..6ed836c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -20,18 +20,18 @@
 import android.os.Handler;
 import android.view.IWindowManager;
 
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.Pip;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.phone.PipAppOpsListener;
 import com.android.systemui.pip.phone.PipController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.pip.phone.PipMediaController;
+import com.android.systemui.pip.phone.PipMenuActivityController;
+import com.android.systemui.pip.phone.PipTouchHandler;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
@@ -66,21 +66,17 @@
     @SysUISingleton
     @Provides
     static Pip providePipController(Context context,
-            BroadcastDispatcher broadcastDispatcher,
-            ConfigurationController configController,
-            DeviceConfigProxy deviceConfig,
             DisplayController displayController,
-            FloatingContentCoordinator floatingContentCoordinator,
-            SysUiState sysUiState,
+            PipAppOpsListener pipAppOpsListener,
             PipBoundsHandler pipBoundsHandler,
-            PipSurfaceTransactionHelper surfaceTransactionHelper,
+            PipMediaController pipMediaController,
+            PipMenuActivityController pipMenuActivityController,
             PipTaskOrganizer pipTaskOrganizer,
-            PipUiEventLogger pipUiEventLogger) {
-        return new PipController(context, broadcastDispatcher, configController, deviceConfig,
-                displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
-                surfaceTransactionHelper,
-                pipTaskOrganizer,
-                pipUiEventLogger);
+            PipTouchHandler pipTouchHandler,
+            WindowManagerShellWrapper windowManagerShellWrapper) {
+        return new PipController(context, displayController,
+                pipAppOpsListener, pipBoundsHandler, pipMediaController, pipMenuActivityController,
+                pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper);
     }
 
     @SysUISingleton
@@ -101,6 +97,24 @@
 
     @SysUISingleton
     @Provides
+    static PipMenuActivityController providesPipMenuActivityController(Context context,
+            PipMediaController pipMediaController, PipTaskOrganizer pipTaskOrganizer) {
+        return new PipMenuActivityController(context, pipMediaController, pipTaskOrganizer);
+    }
+
+    @SysUISingleton
+    @Provides
+    static PipTouchHandler providesPipTouchHandler(Context context,
+            PipMenuActivityController menuActivityController, PipBoundsHandler pipBoundsHandler,
+            PipTaskOrganizer pipTaskOrganizer,
+            FloatingContentCoordinator floatingContentCoordinator,
+            PipUiEventLogger pipUiEventLogger) {
+        return new PipTouchHandler(context, menuActivityController, pipBoundsHandler,
+                pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
+    }
+
+    @SysUISingleton
+    @Provides
     static PipTaskOrganizer providesPipTaskOrganizer(Context context,
             PipBoundsHandler pipBoundsHandler,
             PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java
new file mode 100644
index 0000000..178d472
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellWrapper.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.WindowConfiguration;
+import android.os.RemoteException;
+import android.view.WindowManagerGlobal;
+
+import com.android.systemui.shared.system.PinnedStackListenerForwarder;
+
+/**
+ * The singleton wrapper to communicate between WindowManagerService and WMShell features
+ * (e.g: PIP, SplitScreen, Bubble, OneHandedMode...etc)
+ */
+public class WindowManagerShellWrapper {
+    private static final String TAG = WindowManagerShellWrapper.class.getSimpleName();
+
+    public static final int WINDOWING_MODE_PINNED = WindowConfiguration.WINDOWING_MODE_PINNED;
+
+    /**
+     * Forwarder to which we can add multiple pinned stack listeners. Each listener will receive
+     * updates from the window manager service.
+     */
+    private PinnedStackListenerForwarder mPinnedStackListenerForwarder =
+            new PinnedStackListenerForwarder();
+
+    /**
+     * Adds a pinned stack listener, which will receive updates from the window manager service
+     * along with any other pinned stack listeners that were added via this method.
+     */
+    public void addPinnedStackListener(PinnedStackListenerForwarder.PinnedStackListener listener)
+            throws
+            RemoteException {
+        mPinnedStackListenerForwarder.addListener(listener);
+        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
+                DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
+    }
+
+    /**
+     * Removes a pinned stack listener.
+     */
+    public void removePinnedStackListener(
+            PinnedStackListenerForwarder.PinnedStackListener listener) {
+        mPinnedStackListenerForwarder.removeListener(listener);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 66656c5..f6b39c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -45,6 +45,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.IBiometricSysuiReceiver;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintSensorProperties;
@@ -119,8 +120,11 @@
         when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
 
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
-        FingerprintSensorProperties prop = new FingerprintSensorProperties(
-                1, FingerprintSensorProperties.TYPE_UDFPS, true, 1);
+        FingerprintSensorProperties prop = new FingerprintSensorProperties(1 /* sensorId */,
+                SensorProperties.STRENGTH_STRONG,
+                1 /* maxEnrollmentsPerUser */,
+                FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+                true /* resetLockoutRequireHardwareAuthToken */);
         List<FingerprintSensorProperties> props = new ArrayList<>();
         props.add(prop);
         when(mFingerprintManager.getSensorProperties()).thenReturn(props);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index f65c2c9..3b8f1bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 import com.google.common.collect.ImmutableList;
 
@@ -191,6 +192,8 @@
     private LauncherApps mLauncherApps;
     @Mock private LockscreenLockIconController mLockIconController;
 
+    @Mock private WindowManagerShellWrapper mWindowManagerShellWrapper;
+
     private BubbleData mBubbleData;
 
     private TestableLooper mTestableLooper;
@@ -269,6 +272,7 @@
                 mock(INotificationManager.class),
                 mStatusBarService,
                 mWindowManager,
+                mWindowManagerShellWrapper,
                 mLauncherApps);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index dd191e9..cfbd398 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -185,6 +186,8 @@
     private IStatusBarService mStatusBarService;
     @Mock
     private LauncherApps mLauncherApps;
+    @Mock
+    private WindowManagerShellWrapper mWindowManagerShellWrapper;
 
     private BubbleData mBubbleData;
 
@@ -271,6 +274,7 @@
                 mock(INotificationManager.class),
                 mStatusBarService,
                 mWindowManager,
+                mWindowManagerShellWrapper,
                 mLauncherApps);
         mBubbleController.addNotifCallback(mNotifCallback);
         mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index 58b27f2..ec9571a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 
 /**
  * Testable BubbleController subclass that immediately synchronizes surfaces.
@@ -63,6 +64,7 @@
             INotificationManager notificationManager,
             IStatusBarService statusBarService,
             WindowManager windowManager,
+            WindowManagerShellWrapper windowManagerShellWrapper,
             LauncherApps launcherApps) {
         super(context,
                 notificationShadeWindowController, statusBarStateController, shadeController,
@@ -70,7 +72,7 @@
                 zenModeController, lockscreenUserManager, groupManager, entryManager,
                 notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
                 dataRepository, sysUiState, notificationManager, statusBarService,
-                windowManager, launcherApps);
+                windowManager, windowManagerShellWrapper, launcherApps);
         setInflateSynchronously(true);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index fdb432c..ab3b208 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -16,13 +16,12 @@
 
 package com.android.systemui.media
 
-import android.app.Notification
 import android.graphics.drawable.Drawable
-import android.media.MediaMetadata
 import android.media.MediaRouter2Manager
 import android.media.RoutingSessionInfo
+import android.media.session.MediaController
+import android.media.session.MediaController.PlaybackInfo
 import android.media.session.MediaSession
-import android.media.session.PlaybackState
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
@@ -55,7 +54,6 @@
 private const val KEY_OLD = "TEST_KEY_OLD"
 private const val PACKAGE = "PKG"
 private const val SESSION_KEY = "SESSION_KEY"
-private const val SESSION_ARTIST = "SESSION_ARTIST"
 private const val SESSION_TITLE = "SESSION_TITLE"
 private const val DEVICE_NAME = "DEVICE_NAME"
 private const val USER_ID = 0
@@ -68,6 +66,7 @@
 public class MediaDeviceManagerTest : SysuiTestCase() {
 
     private lateinit var manager: MediaDeviceManager
+    @Mock private lateinit var controllerFactory: MediaControllerFactory
     @Mock private lateinit var lmmFactory: LocalMediaManagerFactory
     @Mock private lateinit var lmm: LocalMediaManager
     @Mock private lateinit var mr2: MediaRouter2Manager
@@ -78,10 +77,9 @@
     @Mock private lateinit var device: MediaDevice
     @Mock private lateinit var icon: Drawable
     @Mock private lateinit var route: RoutingSessionInfo
+    @Mock private lateinit var controller: MediaController
+    @Mock private lateinit var playbackInfo: PlaybackInfo
     private lateinit var session: MediaSession
-    private lateinit var metadataBuilder: MediaMetadata.Builder
-    private lateinit var playbackBuilder: PlaybackState.Builder
-    private lateinit var notifBuilder: Notification.Builder
     private lateinit var mediaData: MediaData
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
@@ -89,8 +87,8 @@
     fun setUp() {
         fakeFgExecutor = FakeExecutor(FakeSystemClock())
         fakeBgExecutor = FakeExecutor(FakeSystemClock())
-        manager = MediaDeviceManager(context, lmmFactory, mr2, fakeFgExecutor, fakeBgExecutor,
-                dumpster)
+        manager = MediaDeviceManager(controllerFactory, lmmFactory, mr2, fakeFgExecutor,
+                fakeBgExecutor, dumpster)
         manager.addListener(listener)
 
         // Configure mocks.
@@ -101,28 +99,13 @@
         whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
 
         // Create a media sesssion and notification for testing.
-        metadataBuilder = MediaMetadata.Builder().apply {
-            putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
-            putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
-        }
-        playbackBuilder = PlaybackState.Builder().apply {
-            setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
-            setActions(PlaybackState.ACTION_PLAY)
-        }
-        session = MediaSession(context, SESSION_KEY).apply {
-            setMetadata(metadataBuilder.build())
-            setPlaybackState(playbackBuilder.build())
-        }
-        session.setActive(true)
-        notifBuilder = Notification.Builder(context, "NONE").apply {
-            setContentTitle(SESSION_TITLE)
-            setContentText(SESSION_ARTIST)
-            setSmallIcon(android.R.drawable.ic_media_pause)
-            setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
-        }
+        session = MediaSession(context, SESSION_KEY)
+
         mediaData = MediaData(USER_ID, true, 0, PACKAGE, null, null, SESSION_TITLE, null,
             emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null,
             device = null, active = true, resumeAction = null)
+        whenever(controllerFactory.create(session.sessionToken))
+                .thenReturn(controller)
     }
 
     @After
@@ -336,6 +319,41 @@
         assertThat(data.icon).isNull()
     }
 
+    @Test
+    fun audioInfoChanged() {
+        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
+        whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
+        // GIVEN a controller with local playback type
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        reset(mr2)
+        // WHEN onAudioInfoChanged fires with remote playback type
+        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+        val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
+        verify(controller).registerCallback(captor.capture())
+        captor.value.onAudioInfoChanged(playbackInfo)
+        // THEN the route is checked
+        verify(mr2).getRoutingSessionForMediaController(eq(controller))
+    }
+
+    @Test
+    fun audioInfoHasntChanged() {
+        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+        whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
+        // GIVEN a controller with remote playback type
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        reset(mr2)
+        // WHEN onAudioInfoChanged fires with remote playback type
+        val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
+        verify(controller).registerCallback(captor.capture())
+        captor.value.onAudioInfoChanged(playbackInfo)
+        // THEN the route is not checked
+        verify(mr2, never()).getRoutingSessionForMediaController(eq(controller))
+    }
+
     fun captureCallback(): LocalMediaManager.DeviceCallback {
         val captor = ArgumentCaptor.forClass(LocalMediaManager.DeviceCallback::class.java)
         verify(lmm).registerCallback(captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
new file mode 100644
index 0000000..5d81de6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.content.pm.ServiceInfo
+import android.graphics.Color
+import android.media.MediaDescription
+import android.media.session.MediaSession
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.After
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+private const val KEY = "TEST_KEY"
+private const val OLD_KEY = "RESUME_KEY"
+private const val APP = "APP"
+private const val BG_COLOR = Color.RED
+private const val PACKAGE_NAME = "PKG"
+private const val CLASS_NAME = "CLASS"
+private const val ARTIST = "ARTIST"
+private const val TITLE = "TITLE"
+private const val USER_ID = 0
+private const val MEDIA_PREFERENCES = "media_control_prefs"
+private const val RESUME_COMPONENTS = "package1/class1:package2/class2:package3/class3"
+
+private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+private fun <T> any(): T = Mockito.any<T>()
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class MediaResumeListenerTest : SysuiTestCase() {
+
+    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock private lateinit var mediaDataManager: MediaDataManager
+    @Mock private lateinit var device: MediaDeviceData
+    @Mock private lateinit var token: MediaSession.Token
+    @Mock private lateinit var tunerService: TunerService
+    @Mock private lateinit var resumeBrowserFactory: ResumeMediaBrowserFactory
+    @Mock private lateinit var resumeBrowser: ResumeMediaBrowser
+    @Mock private lateinit var sharedPrefs: SharedPreferences
+    @Mock private lateinit var sharedPrefsEditor: SharedPreferences.Editor
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var pendingIntent: PendingIntent
+
+    @Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
+
+    private lateinit var executor: FakeExecutor
+    private lateinit var data: MediaData
+    private lateinit var resumeListener: MediaResumeListener
+
+    private var originalQsSetting = Settings.Global.getInt(context.contentResolver,
+        Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1)
+    private var originalResumeSetting = Settings.Secure.getInt(context.contentResolver,
+        Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        Settings.Global.putInt(context.contentResolver,
+            Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1)
+        Settings.Secure.putInt(context.contentResolver,
+            Settings.Secure.MEDIA_CONTROLS_RESUME, 1)
+
+        whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
+                .thenReturn(resumeBrowser)
+
+        // resume components are stored in sharedpreferences
+        whenever(mockContext.getSharedPreferences(eq(MEDIA_PREFERENCES), anyInt()))
+                .thenReturn(sharedPrefs)
+        whenever(sharedPrefs.getString(any(), any())).thenReturn(RESUME_COMPONENTS)
+        whenever(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
+        whenever(sharedPrefsEditor.putString(any(), any())).thenReturn(sharedPrefsEditor)
+        whenever(mockContext.packageManager).thenReturn(context.packageManager)
+        whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
+
+        executor = FakeExecutor(FakeSystemClock())
+        resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
+                tunerService, resumeBrowserFactory)
+        resumeListener.setManager(mediaDataManager)
+        mediaDataManager.addListener(resumeListener)
+
+        data = MediaData(
+                userId = USER_ID,
+                initialized = true,
+                backgroundColor = BG_COLOR,
+                app = APP,
+                appIcon = null,
+                artist = ARTIST,
+                song = TITLE,
+                artwork = null,
+                actions = emptyList(),
+                actionsToShowInCompact = emptyList(),
+                packageName = PACKAGE_NAME,
+                token = token,
+                clickIntent = null,
+                device = device,
+                active = true,
+                notificationKey = KEY,
+                resumeAction = null)
+    }
+
+    @After
+    fun tearDown() {
+        Settings.Global.putInt(context.contentResolver,
+            Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, originalQsSetting)
+        Settings.Secure.putInt(context.contentResolver,
+            Settings.Secure.MEDIA_CONTROLS_RESUME, originalResumeSetting)
+    }
+
+    @Test
+    fun testWhenNoResumption_doesNothing() {
+        Settings.Secure.putInt(context.contentResolver,
+            Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
+
+        // When listener is created, we do NOT register a user change listener
+        val listener = MediaResumeListener(context, broadcastDispatcher, executor, tunerService,
+                resumeBrowserFactory)
+        listener.setManager(mediaDataManager)
+        verify(broadcastDispatcher, never()).registerReceiver(eq(listener.userChangeReceiver),
+            any(), any(), any())
+
+        // When data is loaded, we do NOT execute or update anything
+        listener.onMediaDataLoaded(KEY, OLD_KEY, data)
+        assertThat(executor.numPending()).isEqualTo(0)
+        verify(mediaDataManager, never()).setResumeAction(any(), any())
+    }
+
+    @Test
+    fun testOnLoad_checksForResume_noService() {
+        // When media data is loaded that has not been checked yet, and does not have a MBS
+        resumeListener.onMediaDataLoaded(KEY, null, data)
+
+        // Then we report back to the manager
+        verify(mediaDataManager).setResumeAction(KEY, null)
+    }
+
+    @Test
+    fun testOnLoad_checksForResume_hasService() {
+        // Set up mocks to successfully find a MBS that returns valid media
+        val pm = mock(PackageManager::class.java)
+        whenever(mockContext.packageManager).thenReturn(pm)
+        val resolveInfo = ResolveInfo()
+        val serviceInfo = ServiceInfo()
+        serviceInfo.packageName = PACKAGE_NAME
+        resolveInfo.serviceInfo = serviceInfo
+        resolveInfo.serviceInfo.name = CLASS_NAME
+        val resumeInfo = listOf(resolveInfo)
+        whenever(pm.queryIntentServices(any(), anyInt())).thenReturn(resumeInfo)
+
+        val description = MediaDescription.Builder().setTitle(TITLE).build()
+        val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+        whenever(resumeBrowser.testConnection()).thenAnswer {
+            callbackCaptor.value.addTrack(description, component, resumeBrowser)
+        }
+
+        // When media data is loaded that has not been checked yet, and does have a MBS
+        val dataCopy = data.copy(resumeAction = null, hasCheckedForResume = false)
+        resumeListener.onMediaDataLoaded(KEY, null, dataCopy)
+
+        // Then we test whether the service is valid
+        executor.runAllReady()
+        verify(resumeBrowser).testConnection()
+
+        // And since it is, we report back to the manager
+        verify(mediaDataManager).setResumeAction(eq(KEY), any())
+
+        // But we do not tell it to add new controls
+        verify(mediaDataManager, never())
+                .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
+
+        // Finally, make sure the resume browser disconnected
+        verify(resumeBrowser).disconnect()
+    }
+
+    @Test
+    fun testOnLoad_doesNotCheckAgain() {
+        // When a media data is loaded that has been checked already
+        var dataCopy = data.copy(hasCheckedForResume = true)
+        resumeListener.onMediaDataLoaded(KEY, null, dataCopy)
+
+        // Then we should not check it again
+        verify(resumeBrowser, never()).testConnection()
+        verify(mediaDataManager, never()).setResumeAction(KEY, null)
+    }
+
+    @Test
+    fun testOnUserUnlock_loadsTracks() {
+        // Set up mock service to successfully find valid media
+        val description = MediaDescription.Builder().setTitle(TITLE).build()
+        val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+        whenever(resumeBrowser.token).thenReturn(token)
+        whenever(resumeBrowser.appIntent).thenReturn(pendingIntent)
+        whenever(resumeBrowser.findRecentMedia()).thenAnswer {
+            callbackCaptor.value.addTrack(description, component, resumeBrowser)
+        }
+
+        // Make sure broadcast receiver is registered
+        resumeListener.setManager(mediaDataManager)
+        verify(broadcastDispatcher).registerReceiver(eq(resumeListener.userChangeReceiver),
+                any(), any(), any())
+
+        // When we get an unlock event
+        val intent = Intent(Intent.ACTION_USER_UNLOCKED)
+        resumeListener.userChangeReceiver.onReceive(context, intent)
+
+        // Then we should attempt to find recent media for each saved component
+        verify(resumeBrowser, times(3)).findRecentMedia()
+
+        // Then since the mock service found media, the manager should be informed
+        verify(mediaDataManager, times(3)).addResumptionControls(anyInt(),
+                any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index f385243..f397959 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -23,8 +23,9 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
@@ -33,7 +34,6 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.ArgumentMatchers.anyString
 import org.mockito.Captor
 import org.mockito.Mock
@@ -63,10 +63,8 @@
 
     @Mock private lateinit var mediaControllerFactory: MediaControllerFactory
     @Mock private lateinit var mediaController: MediaController
-    @Mock private lateinit var executor: DelayableExecutor
+    private lateinit var executor: FakeExecutor
     @Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
-    @Mock private lateinit var cancellationRunnable: Runnable
-    @Captor private lateinit var timeoutCaptor: ArgumentCaptor<Runnable>
     @Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
     @JvmField @Rule val mockito = MockitoJUnit.rule()
     private lateinit var metadataBuilder: MediaMetadata.Builder
@@ -78,7 +76,7 @@
     @Before
     fun setup() {
         `when`(mediaControllerFactory.create(any())).thenReturn(mediaController)
-        `when`(executor.executeDelayed(any(), anyLong())).thenReturn(cancellationRunnable)
+        executor = FakeExecutor(FakeSystemClock())
         mediaTimeoutListener = MediaTimeoutListener(mediaControllerFactory, executor)
         mediaTimeoutListener.timeoutCallback = timeoutCallback
 
@@ -120,7 +118,7 @@
     fun testOnMediaDataLoaded_registersTimeout_whenPaused() {
         mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
         verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
-        verify(executor).executeDelayed(capture(timeoutCaptor), anyLong())
+        assertThat(executor.numPending()).isEqualTo(1)
         verify(timeoutCallback, never()).invoke(anyString(), anyBoolean())
     }
 
@@ -137,6 +135,17 @@
     }
 
     @Test
+    fun testOnMediaDataRemoved_clearsTimeout() {
+        // GIVEN media that is paused
+        mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
+        assertThat(executor.numPending()).isEqualTo(1)
+        // WHEN the media is removed
+        mediaTimeoutListener.onMediaDataRemoved(KEY)
+        // THEN the timeout runnable is cancelled
+        assertThat(executor.numPending()).isEqualTo(0)
+    }
+
+    @Test
     fun testOnMediaDataLoaded_migratesKeys() {
         // From not playing
         mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
@@ -151,7 +160,7 @@
         verify(mediaController).registerCallback(anyObject())
 
         // Enqueues callback
-        verify(executor).execute(anyObject())
+        assertThat(executor.numPending()).isEqualTo(1)
     }
 
     @Test
@@ -166,8 +175,9 @@
         `when`(mediaController.playbackState).thenReturn(playingState)
         mediaTimeoutListener.onMediaDataLoaded("NEWKEY", KEY, mediaData)
 
-        // Never cancels callback, or schedule another one
-        verify(cancellationRunnable, never()).run()
+        // The number of queued timeout tasks remains the same. The timeout task isn't cancelled nor
+        // is another scheduled
+        assertThat(executor.numPending()).isEqualTo(1)
     }
 
     @Test
@@ -177,7 +187,7 @@
 
         mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
                 .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
-        verify(executor).executeDelayed(capture(timeoutCaptor), anyLong())
+        assertThat(executor.numPending()).isEqualTo(1)
     }
 
     @Test
@@ -187,7 +197,7 @@
 
         mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
                 .setState(PlaybackState.STATE_PLAYING, 0L, 0f).build())
-        verify(cancellationRunnable).run()
+        assertThat(executor.numPending()).isEqualTo(0)
     }
 
     @Test
@@ -195,10 +205,9 @@
         // Assuming we have a pending timeout
         testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
 
-        clearInvocations(cancellationRunnable)
         mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
                 .setState(PlaybackState.STATE_STOPPED, 0L, 0f).build())
-        verify(cancellationRunnable, never()).run()
+        assertThat(executor.numPending()).isEqualTo(1)
     }
 
     @Test
@@ -206,7 +215,10 @@
         // Assuming we're have a pending timeout
         testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
 
-        timeoutCaptor.value.run()
+        with(executor) {
+            advanceClockToNext()
+            runAllReady()
+        }
         verify(timeoutCallback).invoke(eq(KEY), eq(true))
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
new file mode 100644
index 0000000..d26229e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.content.ComponentName
+import android.content.Context
+import android.media.MediaDescription
+import android.media.browse.MediaBrowser
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.service.media.MediaBrowserService
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+private const val PACKAGE_NAME = "package"
+private const val CLASS_NAME = "class"
+private const val TITLE = "song title"
+private const val MEDIA_ID = "media ID"
+private const val ROOT = "media browser root"
+
+private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+private fun <T> any(): T = Mockito.any<T>()
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+public class ResumeMediaBrowserTest : SysuiTestCase() {
+
+    private lateinit var resumeBrowser: TestableResumeMediaBrowser
+    private val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+    private val description = MediaDescription.Builder()
+            .setTitle(TITLE)
+            .setMediaId(MEDIA_ID)
+            .build()
+
+    @Mock lateinit var callback: ResumeMediaBrowser.Callback
+    @Mock lateinit var listener: MediaResumeListener
+    @Mock lateinit var service: MediaBrowserService
+    @Mock lateinit var browserFactory: MediaBrowserFactory
+    @Mock lateinit var browser: MediaBrowser
+    @Mock lateinit var token: MediaSession.Token
+    @Mock lateinit var mediaController: MediaController
+    @Mock lateinit var transportControls: MediaController.TransportControls
+
+    @Captor lateinit var connectionCallback: ArgumentCaptor<MediaBrowser.ConnectionCallback>
+    @Captor lateinit var subscriptionCallback: ArgumentCaptor<MediaBrowser.SubscriptionCallback>
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(browserFactory.create(any(), capture(connectionCallback), any()))
+                .thenReturn(browser)
+
+        whenever(mediaController.transportControls).thenReturn(transportControls)
+
+        resumeBrowser = TestableResumeMediaBrowser(context, callback, component, browserFactory,
+                mediaController)
+    }
+
+    @Test
+    fun testConnection_connectionFails_callsOnError() {
+        // When testConnection cannot connect to the service
+        setupBrowserFailed()
+        resumeBrowser.testConnection()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testConnection_connects_onConnected() {
+        // When testConnection can connect to the service
+        setupBrowserConnection()
+        resumeBrowser.testConnection()
+
+        // Then it calls onConnected
+        verify(callback).onConnected()
+    }
+
+    @Test
+    fun testConnection_noValidMedia_error() {
+        // When testConnection can connect to the service, and does not find valid media
+        setupBrowserConnectionNoResults()
+        resumeBrowser.testConnection()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testConnection_hasValidMedia_addTrack() {
+        // When testConnection can connect to the service, and finds valid media
+        setupBrowserConnectionValidMedia()
+        resumeBrowser.testConnection()
+
+        // Then it calls addTrack
+        verify(callback).onConnected()
+        verify(callback).addTrack(eq(description), eq(component), eq(resumeBrowser))
+    }
+
+    @Test
+    fun testFindRecentMedia_connectionFails_error() {
+        // When findRecentMedia is called and we cannot connect
+        setupBrowserFailed()
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testFindRecentMedia_noRoot_error() {
+        // When findRecentMedia is called and does not get a valid root
+        setupBrowserConnection()
+        whenever(browser.getRoot()).thenReturn(null)
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testFindRecentMedia_connects_onConnected() {
+        // When findRecentMedia is called and we connect
+        setupBrowserConnection()
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls onConnected
+        verify(callback).onConnected()
+    }
+
+    @Test
+    fun testFindRecentMedia_noChildren_error() {
+        // When findRecentMedia is called and we connect, but do not get any results
+        setupBrowserConnectionNoResults()
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testFindRecentMedia_notPlayable_error() {
+        // When findRecentMedia is called and we connect, but do not get a playable child
+        setupBrowserConnectionNotPlayable()
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testFindRecentMedia_hasValidMedia_addTrack() {
+        // When findRecentMedia is called and we can connect and get playable media
+        setupBrowserConnectionValidMedia()
+        resumeBrowser.findRecentMedia()
+
+        // Then it calls addTrack
+        verify(callback).addTrack(eq(description), eq(component), eq(resumeBrowser))
+    }
+
+    @Test
+    fun testRestart_connectionFails_error() {
+        // When restart is called and we cannot connect
+        setupBrowserFailed()
+        resumeBrowser.restart()
+
+        // Then it calls onError
+        verify(callback).onError()
+    }
+
+    @Test
+    fun testRestart_connects() {
+        // When restart is called and we connect successfully
+        setupBrowserConnection()
+        resumeBrowser.restart()
+
+        // Then it creates a new controller and sends play command
+        verify(transportControls).prepare()
+        verify(transportControls).play()
+
+        // Then it calls onConnected
+        verify(callback).onConnected()
+    }
+
+    /**
+     * Helper function to mock a failed connection
+     */
+    private fun setupBrowserFailed() {
+        whenever(browser.connect()).thenAnswer {
+            connectionCallback.value.onConnectionFailed()
+        }
+    }
+
+    /**
+     * Helper function to mock a successful connection only
+     */
+    private fun setupBrowserConnection() {
+        whenever(browser.connect()).thenAnswer {
+            connectionCallback.value.onConnected()
+        }
+        whenever(browser.isConnected()).thenReturn(true)
+        whenever(browser.getRoot()).thenReturn(ROOT)
+        whenever(browser.sessionToken).thenReturn(token)
+    }
+
+    /**
+     * Helper function to mock a successful connection, but no media results
+     */
+    private fun setupBrowserConnectionNoResults() {
+        setupBrowserConnection()
+        whenever(browser.subscribe(any(), capture(subscriptionCallback))).thenAnswer {
+            subscriptionCallback.value.onChildrenLoaded(ROOT, emptyList())
+        }
+    }
+
+    /**
+     * Helper function to mock a successful connection, but no playable results
+     */
+    private fun setupBrowserConnectionNotPlayable() {
+        setupBrowserConnection()
+
+        val child = MediaBrowser.MediaItem(description, 0)
+
+        whenever(browser.subscribe(any(), capture(subscriptionCallback))).thenAnswer {
+            subscriptionCallback.value.onChildrenLoaded(ROOT, listOf(child))
+        }
+    }
+
+    /**
+     * Helper function to mock a successful connection with playable media
+     */
+    private fun setupBrowserConnectionValidMedia() {
+        setupBrowserConnection()
+
+        val child = MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_PLAYABLE)
+
+        whenever(browser.serviceComponent).thenReturn(component)
+        whenever(browser.subscribe(any(), capture(subscriptionCallback))).thenAnswer {
+            subscriptionCallback.value.onChildrenLoaded(ROOT, listOf(child))
+        }
+    }
+
+    /**
+     * Override so media controller use is testable
+     */
+    private class TestableResumeMediaBrowser(
+        context: Context,
+        callback: Callback,
+        componentName: ComponentName,
+        browserFactory: MediaBrowserFactory,
+        private val fakeController: MediaController
+    ) : ResumeMediaBrowser(context, callback, componentName, browserFactory) {
+
+        override fun createMediaController(token: MediaSession.Token): MediaController {
+            return fakeController
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 42b21c6..27b5b7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -36,7 +36,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
@@ -55,7 +54,6 @@
 
     // Mock
     private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
-
     private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
     private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
     private ShadeController mShadeController = mock(ShadeController.class);
@@ -157,30 +155,6 @@
         verify(mMediaOutputBaseAdapter).notifyDataSetChanged();
     }
 
-    @Test
-    public void refresh_with6Devices_checkBottomPaddingVisibility() {
-        for (int i = 0; i < 6; i++) {
-            mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
-        }
-        mMediaOutputBaseDialogImpl.refresh();
-        final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
-                R.id.list_bottom_padding);
-
-        assertThat(view.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void refresh_with5Devices_checkBottomPaddingVisibility() {
-        for (int i = 0; i < 5; i++) {
-            mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
-        }
-        mMediaOutputBaseDialogImpl.refresh();
-        final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
-                R.id.list_bottom_padding);
-
-        assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
     class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
 
         MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
@@ -189,24 +163,34 @@
             mAdapter = mMediaOutputBaseAdapter;
         }
 
+        @Override
         int getHeaderIconRes() {
             return mHeaderIconRes;
         }
 
+        @Override
         IconCompat getHeaderIcon() {
             return mIconCompat;
         }
 
+        @Override
         int getHeaderIconSize() {
             return 10;
         }
 
+        @Override
         CharSequence getHeaderText() {
             return mHeaderTitle;
         }
 
+        @Override
         CharSequence getHeaderSubtitle() {
             return mHeaderSubtitle;
         }
+
+        @Override
+        int getStopButtonVisibility() {
+            return 0;
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
new file mode 100644
index 0000000..ca328fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.MediaRoute2Info;
+import android.media.session.MediaSessionManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.ShadeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MediaOutputDialogTest extends SysuiTestCase {
+
+    private static final String TEST_PACKAGE = "test_package";
+
+    // Mock
+    private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
+    private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+    private ShadeController mShadeController = mock(ShadeController.class);
+    private ActivityStarter mStarter = mock(ActivityStarter.class);
+    private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
+    private MediaDevice mMediaDevice = mock(MediaDevice.class);
+
+    private MediaOutputDialog mMediaOutputDialog;
+    private MediaOutputController mMediaOutputController;
+    private List<String> mFeatures = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+                mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter);
+        mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
+        mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController);
+
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
+        when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
+    }
+
+    @Test
+    public void getStopButtonVisibility_remoteDevice_returnVisible() {
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void getStopButtonVisibility_localDevice_returnGone() {
+        mFeatures.add(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 6f5cbe2..89ca32c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.graphics.Matrix;
@@ -34,7 +33,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,7 +59,7 @@
     @Before
     public void setUp() throws Exception {
         mPipAnimationController = new PipAnimationController(
-                new PipSurfaceTransactionHelper(mContext, mock(ConfigurationController.class)));
+                new PipSurfaceTransactionHelper(mContext));
         mLeash = new SurfaceControl.Builder()
                 .setContainerLayer()
                 .setName("FakeLeash")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java
index b043495..1274621 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipControllerTest.java
@@ -32,16 +32,11 @@
 import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipBoundsHandler;
-import com.android.systemui.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.DeviceConfigProxy;
-import com.android.systemui.util.FloatingContentCoordinator;
+import com.android.systemui.wmshell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
 
 import org.junit.Before;
@@ -61,17 +56,16 @@
     private TestableContext mSpiedContext;
 
     @Mock private ActivityManagerWrapper mMockActivityManagerWrapper;
-    @Mock private BroadcastDispatcher mMockBroadcastDispatcher;
     @Mock private ConfigurationController mMockConfigurationController;
-    @Mock private DeviceConfigProxy mMockDeviceConfigProxy;
     @Mock private DisplayController mMockdDisplayController;
-    @Mock private FloatingContentCoordinator mMockFloatingContentCoordinator;
     @Mock private PackageManager mPackageManager;
+    @Mock private PipMenuActivityController mMockPipMenuActivityController;
+    @Mock private PipAppOpsListener mMockPipAppOpsListener;
     @Mock private PipBoundsHandler mMockPipBoundsHandler;
-    @Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
+    @Mock private PipMediaController mMockPipMediaController;
     @Mock private PipTaskOrganizer mMockPipTaskOrganizer;
-    @Mock private PipUiEventLogger mPipUiEventLogger;
-    @Mock private SysUiState mMockSysUiState;
+    @Mock private PipTouchHandler mMockPipTouchHandler;
+    @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
 
     @Before
     public void setUp() throws RemoteException {
@@ -82,10 +76,10 @@
         when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
         when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
 
-        mPipController = new PipController(mSpiedContext, mMockBroadcastDispatcher,
-                mMockConfigurationController, mMockDeviceConfigProxy, mMockdDisplayController,
-                mMockFloatingContentCoordinator, mMockSysUiState, mMockPipBoundsHandler,
-                mMockPipSurfaceTransactionHelper, mMockPipTaskOrganizer, mPipUiEventLogger);
+        mPipController = new PipController(mSpiedContext, mMockdDisplayController,
+                mMockPipAppOpsListener,
+                mMockPipBoundsHandler, mMockPipMediaController, mMockPipMenuActivityController,
+                mMockPipTaskOrganizer, mMockPipTouchHandler, mMockWindowManagerShellWrapper);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index c8d4aca..ad83ebb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -22,7 +22,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.app.IActivityManager;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
@@ -33,13 +32,10 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.pip.PipUiEventLogger;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.FloatingContentCoordinator;
 
 import org.junit.Before;
@@ -63,27 +59,15 @@
     private PipTouchHandler mPipTouchHandler;
 
     @Mock
-    private IActivityManager mActivityManager;
-
-    @Mock
     private PipMenuActivityController mPipMenuActivityController;
 
     @Mock
-    private InputConsumerController mInputConsumerController;
-
-    @Mock
     private PipTaskOrganizer mPipTaskOrganizer;
 
     @Mock
     private FloatingContentCoordinator mFloatingContentCoordinator;
 
     @Mock
-    private DeviceConfigProxy mDeviceConfigProxy;
-
-    @Mock
-    private SysUiState mSysUiState;
-
-    @Mock
     private PipUiEventLogger mPipUiEventLogger;
 
     private PipBoundsHandler mPipBoundsHandler;
@@ -105,9 +89,8 @@
         mPipBoundsHandler = new PipBoundsHandler(mContext);
         mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
         mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
-        mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
-                mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
-                mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy, mSysUiState,
+        mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
+                mPipBoundsHandler, mPipTaskOrganizer, mFloatingContentCoordinator,
                 mPipUiEventLogger);
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
         mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
index 402a99d..dee6020 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AlertingNotificationManagerTest.java
@@ -108,11 +108,7 @@
         return new TestableAlertingNotificationManager();
     }
 
-    protected StatusBarNotification createNewNotification(int id) {
-        Notification.Builder n = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
+    protected StatusBarNotification createNewSbn(int id, Notification.Builder n) {
         return new StatusBarNotification(
                 TEST_PACKAGE_NAME /* pkg */,
                 TEST_PACKAGE_NAME,
@@ -126,6 +122,14 @@
                 0 /* postTime */);
     }
 
+    protected StatusBarNotification createNewNotification(int id) {
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        return createNewSbn(id, n);
+    }
+
     @Before
     public void setUp() {
         mTestHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index a36a4c4..0bf1ac3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -45,6 +45,7 @@
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.doThrow
 import org.mockito.Mockito.never
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 
@@ -79,6 +80,7 @@
     @Before
     fun setup() {
         `when`(root.viewRootImpl).thenReturn(viewRootImpl)
+        `when`(root.isAttachedToWindow).thenReturn(true)
         `when`(statusBarStateController.state).then { statusBarState }
         `when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
             (answer.arguments[0] as Float * maxBlur).toInt()
@@ -219,6 +221,13 @@
 
     @Test
     fun updateBlurCallback_invalidWindow() {
+        `when`(root.isAttachedToWindow).thenReturn(false)
+        notificationShadeDepthController.updateBlurCallback.doFrame(0)
+        verify(wallpaperManager, times(0)).setWallpaperZoomOut(any(), anyFloat())
+    }
+
+    @Test
+    fun updateBlurCallback_exception() {
         doThrow(IllegalArgumentException("test exception")).`when`(wallpaperManager)
                 .setWallpaperZoomOut(any(), anyFloat())
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index fc7d0ce..0e4b053 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 
+import android.app.Notification;
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -30,6 +33,7 @@
 
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -84,5 +88,25 @@
         assertTrue("Heads up should live long enough", mLivesPastNormalTime);
         assertFalse(mHeadsUpManager.isAlerting(mEntry.getKey()));
     }
+
+    @Test
+    public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
+        HeadsUpManager.HeadsUpEntry ongoingCall = mHeadsUpManager.new HeadsUpEntry();
+        ongoingCall.setEntry(new NotificationEntryBuilder()
+                .setSbn(createNewSbn(0,
+                        new Notification.Builder(mContext, "")
+                                .setCategory(Notification.CATEGORY_CALL)
+                                .setOngoing(true)))
+                .build());
+
+        HeadsUpManager.HeadsUpEntry activeRemoteInput = mHeadsUpManager.new HeadsUpEntry();
+        activeRemoteInput.setEntry(new NotificationEntryBuilder()
+                .setSbn(createNewNotification(1))
+                .build());
+        activeRemoteInput.remoteInputActive = true;
+
+        assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
+        assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0);
+    }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 280423f..0b75950 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -37,9 +37,12 @@
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.phone.PipTouchHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayImeController;
@@ -59,9 +62,11 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class WMShellTest extends SysuiTestCase {
-
+    InputConsumerController mInputConsumerController;
     WMShell mWMShell;
+
     @Mock CommandQueue mCommandQueue;
+    @Mock ConfigurationController mConfigurationController;
     @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock ActivityManagerWrapper mActivityManagerWrapper;
     @Mock DisplayImeController mDisplayImeController;
@@ -69,6 +74,7 @@
     @Mock ScreenLifecycle mScreenLifecycle;
     @Mock SysUiState mSysUiState;
     @Mock Pip mPip;
+    @Mock PipTouchHandler mPipTouchHandler;
     @Mock SplitScreen mSplitScreen;
     @Mock OneHanded mOneHanded;
     @Mock ShellTaskOrganizer mTaskOrganizer;
@@ -78,10 +84,16 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
-                mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
-                mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
-                Optional.of(mOneHanded), mTaskOrganizer, mProtoTracer);
+        mInputConsumerController = InputConsumerController.getPipInputConsumer();
+
+        mWMShell = new WMShell(mContext, mCommandQueue, mConfigurationController,
+                mInputConsumerController, mKeyguardUpdateMonitor, mActivityManagerWrapper,
+                mDisplayImeController, mNavigationModeController, mScreenLifecycle, mSysUiState,
+                Optional.of(mPip), Optional.of(mSplitScreen), Optional.of(mOneHanded),
+                mTaskOrganizer, mProtoTracer);
+
+        when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
+
     }
 
     @Test
@@ -103,9 +115,8 @@
         TestableContext spiedContext = spy(mContext);
         when(mMockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false);
         when(spiedContext.getPackageManager()).thenReturn(mMockPackageManager);
-
         final WMShell nonPipWMShell = new WMShell(spiedContext, mCommandQueue,
-                mKeyguardUpdateMonitor,
+                mConfigurationController, mInputConsumerController, mKeyguardUpdateMonitor,
                 mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
                 mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
                 Optional.of(mOneHanded), mTaskOrganizer, mProtoTracer);
diff --git a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
index f6eb40a..94c871d 100644
--- a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -17,18 +17,63 @@
 #include <errno.h>
 #include <error.h>
 #include <jni.h>
+#include <linux/filter.h>
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/JNIHelpCompat.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <net/if.h>
+#include <netinet/ether.h>
+#include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 #include <sys/socket.h>
+#include <stdio.h>
 
 #define LOG_TAG "TetheringUtils"
 #include <android/log.h>
 
 namespace android {
 
+static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
+static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
+static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+
+static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
+    sock_filter filter_code[] = {
+        // Check header is ICMPv6.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kIPv6NextHeaderOffset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 3),
+
+        // Check ICMPv6 type.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  kICMPv6TypeOffset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    type, 0, 1),
+
+        // Accept or reject.
+        BPF_STMT(BPF_RET | BPF_K,              0xffff),
+        BPF_STMT(BPF_RET | BPF_K,              0)
+    };
+
+    const sock_fprog filter = {
+        sizeof(filter_code) / sizeof(filter_code[0]),
+        filter_code,
+    };
+
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+    }
+}
+
+static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+    android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT);
+}
+
+static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+    android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT);
+}
+
 static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
         jint ifIndex)
 {
@@ -125,7 +170,12 @@
  */
 static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
+    { "setupNaSocket", "(Ljava/io/FileDescriptor;)V",
+        (void*) android_net_util_setupNaSocket },
+    { "setupNsSocket", "(Ljava/io/FileDescriptor;)V",
+        (void*) android_net_util_setupNsSocket },
+    { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V",
+        (void*) android_net_util_setupRaSocket },
 };
 
 int register_android_net_util_TetheringUtils(JNIEnv* env) {
diff --git a/packages/Tethering/src/android/net/ip/DadProxy.java b/packages/Tethering/src/android/net/ip/DadProxy.java
new file mode 100644
index 0000000..e2976b7
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/DadProxy.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.util.InterfaceParams;
+import android.os.Handler;
+
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Basic Duplicate address detection proxy.
+ *
+ * @hide
+ */
+public class DadProxy {
+    private static final String TAG = DadProxy.class.getSimpleName();
+
+    @VisibleForTesting
+    public static NeighborPacketForwarder naForwarder;
+    public static NeighborPacketForwarder nsForwarder;
+
+    public DadProxy(Handler h, InterfaceParams tetheredIface) {
+        naForwarder = new NeighborPacketForwarder(h, tetheredIface,
+                                        NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+        nsForwarder = new NeighborPacketForwarder(h, tetheredIface,
+                                        NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+    }
+
+    /** Stop NS/NA Forwarders. */
+    public void stop() {
+        naForwarder.stop();
+        nsForwarder.stop();
+    }
+
+    /** Set upstream iface on both forwarders. */
+    public void setUpstreamIface(InterfaceParams upstreamIface) {
+        naForwarder.setUpstreamIface(upstreamIface);
+        nsForwarder.setUpstreamIface(upstreamIface);
+    }
+}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 673cbf0..336124d 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -51,6 +51,7 @@
 import android.net.util.InterfaceSet;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -160,6 +161,15 @@
 
     /** Capture IpServer dependencies, for injection. */
     public abstract static class Dependencies {
+        /**
+         * Create a DadProxy instance to be used by IpServer.
+         * To support multiple tethered interfaces concurrently DAD Proxy
+         * needs to be supported per IpServer instead of per upstream.
+         */
+        public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) {
+            return new DadProxy(handler, ifParams);
+        }
+
         /** Create an IpNeighborMonitor to be used by this IpServer */
         public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
                 IpNeighborMonitor.NeighborEventConsumer consumer) {
@@ -256,6 +266,7 @@
     // Advertisements (otherwise, we do not add them to mLinkProperties at all).
     private LinkProperties mLastIPv6LinkProperties;
     private RouterAdvertisementDaemon mRaDaemon;
+    private DadProxy mDadProxy;
 
     // To be accessed only on the handler thread
     private int mDhcpServerStartIndex = 0;
@@ -674,6 +685,13 @@
             return false;
         }
 
+        // TODO: use ShimUtils instead of explicitly checking the version here.
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
+                    || "T".equals(Build.VERSION.CODENAME)) {
+            // DAD Proxy starts forwarding packets after IPv6 upstream is present.
+            mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams);
+        }
+
         return true;
     }
 
@@ -685,6 +703,11 @@
             mRaDaemon.stop();
             mRaDaemon = null;
         }
+
+        if (mDadProxy != null) {
+            mDadProxy.stop();
+            mDadProxy = null;
+        }
     }
 
     // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
@@ -702,11 +725,16 @@
         }
 
         RaParams params = null;
-        int upstreamIfindex = 0;
+        String upstreamIface = null;
+        InterfaceParams upstreamIfaceParams = null;
+        int upstreamIfIndex = 0;
 
         if (v6only != null) {
-            final String upstreamIface = v6only.getInterfaceName();
-
+            upstreamIface = v6only.getInterfaceName();
+            upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface);
+            if (upstreamIfaceParams != null) {
+                upstreamIfIndex = upstreamIfaceParams.index;
+            }
             params = new RaParams();
             params.mtu = v6only.getMtu();
             params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
@@ -726,15 +754,13 @@
                 }
             }
 
-            upstreamIfindex = mDeps.getIfindex(upstreamIface);
-
             // Add upstream index to name mapping for the tether stats usage in the coordinator.
             // Although this mapping could be added by both class Tethering and IpServer, adding
             // mapping from IpServer guarantees that the mapping is added before the adding
             // forwarding rules. That is because there are different state machines in both
             // classes. It is hard to guarantee the link property update order between multiple
             // state machines.
-            mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
+            mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
         }
 
         // If v6only is null, we pass in null to setRaParams(), which handles
@@ -743,8 +769,11 @@
         setRaParams(params);
         mLastIPv6LinkProperties = v6only;
 
-        updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null);
-        mLastIPv6UpstreamIfindex = upstreamIfindex;
+        updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
+        mLastIPv6UpstreamIfindex = upstreamIfIndex;
+        if (mDadProxy != null) {
+            mDadProxy.setUpstreamIface(upstreamIfaceParams);
+        }
     }
 
     private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
new file mode 100644
index 0000000..73fc833
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_RAW;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_NONBLOCK;
+import static android.system.OsConstants.SOCK_RAW;
+
+import android.net.util.InterfaceParams;
+import android.net.util.PacketReader;
+import android.net.util.SocketUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * Basic IPv6 Neighbor Advertisement Forwarder.
+ *
+ * Forward NA packets from upstream iface to tethered iface
+ * and NS packets from tethered iface to upstream iface.
+ *
+ * @hide
+ */
+public class NeighborPacketForwarder extends PacketReader {
+    private final String mTag;
+
+    private FileDescriptor mFd;
+
+    // TODO: get these from NetworkStackConstants.
+    private static final int IPV6_ADDR_LEN = 16;
+    private static final int IPV6_DST_ADDR_OFFSET = 24;
+    private static final int IPV6_HEADER_LEN = 40;
+    private static final int ETH_HEADER_LEN = 14;
+
+    private InterfaceParams mListenIfaceParams, mSendIfaceParams;
+
+    private final int mType;
+    public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT  = 136;
+    public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
+
+    public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) {
+        super(h);
+        mTag = NeighborPacketForwarder.class.getSimpleName() + "-"
+                + tetheredInterface.name + "-" + type;
+        mType = type;
+
+        if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+            mSendIfaceParams = tetheredInterface;
+        } else {
+            mListenIfaceParams = tetheredInterface;
+        }
+    }
+
+    /** Set new upstream iface and start/stop based on new params. */
+    public void setUpstreamIface(InterfaceParams upstreamParams) {
+        final InterfaceParams oldUpstreamParams;
+
+        if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+            oldUpstreamParams = mListenIfaceParams;
+            mListenIfaceParams = upstreamParams;
+        } else {
+            oldUpstreamParams = mSendIfaceParams;
+            mSendIfaceParams = upstreamParams;
+        }
+
+        if (oldUpstreamParams == null && upstreamParams != null) {
+            start();
+        } else if (oldUpstreamParams != null && upstreamParams == null) {
+            stop();
+        } else if (oldUpstreamParams != null && upstreamParams != null
+                   && oldUpstreamParams.index != upstreamParams.index) {
+            stop();
+            start();
+        }
+    }
+
+    // TODO: move NetworkStackUtils.closeSocketQuietly to
+    // frameworks/libs/net/common/device/com/android/net/module/util/[someclass].
+    private void closeSocketQuietly(FileDescriptor fd) {
+        try {
+            SocketUtils.closeSocket(fd);
+        } catch (IOException ignored) {
+        }
+    }
+
+    @Override
+    protected FileDescriptor createFd() {
+        try {
+            // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used.
+            // To keep uniformity in both directions PACKET socket can be used.
+            mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+
+            // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type?
+            if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+                TetheringUtils.setupNaSocket(mFd);
+            } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) {
+                TetheringUtils.setupNsSocket(mFd);
+            }
+
+            SocketAddress bindAddress = SocketUtils.makePacketSocketAddress(
+                                                        ETH_P_IPV6, mListenIfaceParams.index);
+            Os.bind(mFd, bindAddress);
+        } catch (ErrnoException | SocketException e) {
+            Log.wtf(mTag, "Failed to create  socket", e);
+            closeSocketQuietly(mFd);
+            return null;
+        }
+
+        return mFd;
+    }
+
+    private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) {
+        Inet6Address dstAddr;
+        try {
+            dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf,
+                    IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN));
+        } catch (UnknownHostException | ClassCastException impossible) {
+            throw new AssertionError("16-byte array not valid IPv6 address?");
+        }
+        return dstAddr;
+    }
+
+    @Override
+    protected void handlePacket(byte[] recvbuf, int length) {
+        if (mSendIfaceParams == null) {
+            return;
+        }
+
+        // The BPF filter should already have checked the length of the packet, but...
+        if (length < IPV6_HEADER_LEN) {
+            return;
+        }
+        Inet6Address destv6 = getIpv6DestinationAddress(recvbuf);
+        if (!destv6.isMulticastAddress()) {
+            return;
+        }
+        InetSocketAddress dest = new InetSocketAddress(destv6, 0);
+
+        FileDescriptor fd = null;
+        try {
+            fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
+            SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name);
+
+            int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest);
+        } catch (ErrnoException | SocketException e) {
+            Log.e(mTag, "handlePacket error: " + e);
+        } finally {
+            closeSocketQuietly(fd);
+        }
+    }
+}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 6f017dc..7c0b7cc7 100644
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -18,6 +18,7 @@
 
 import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+import static android.net.util.TetheringUtils.getAllNodesForScopeId;
 import static android.system.OsConstants.AF_INET6;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
 import static android.system.OsConstants.SOCK_RAW;
@@ -44,7 +45,6 @@
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketException;
-import java.net.UnknownHostException;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -92,10 +92,6 @@
 
     private static final int DAY_IN_SECONDS = 86_400;
 
-    private static final byte[] ALL_NODES = new byte[] {
-            (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
-    };
-
     private final InterfaceParams mInterface;
     private final InetSocketAddress mAllNodes;
 
@@ -240,7 +236,6 @@
         }
     }
 
-
     public RouterAdvertisementDaemon(InterfaceParams ifParams) {
         mInterface = ifParams;
         mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
@@ -363,15 +358,6 @@
         }
     }
 
-    private static Inet6Address getAllNodesForScopeId(int scopeId) {
-        try {
-            return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
-        } catch (UnknownHostException uhe) {
-            Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe);
-            return null;
-        }
-    }
-
     private static byte asByte(int value) {
         return (byte) value;
     }
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index b17b4ba..53b54f7 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -17,11 +17,15 @@
 
 import android.net.TetherStatsParcel;
 import android.net.TetheringRequestParcel;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 
 import java.io.FileDescriptor;
+import java.net.Inet6Address;
 import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -30,6 +34,24 @@
  * {@hide}
  */
 public class TetheringUtils {
+    public static final byte[] ALL_NODES = new byte[] {
+        (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+    };
+
+    /**
+     * Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
+     * @param fd the socket's {@link FileDescriptor}.
+     */
+    public static native void setupNaSocket(FileDescriptor fd)
+            throws SocketException;
+
+    /**
+     * Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
+     * @param fd the socket's {@link FileDescriptor}.
+     */
+    public static native void setupNsSocket(FileDescriptor fd)
+            throws SocketException;
+
     /**
      *  The object which records offload Tx/Rx forwarded bytes/packets.
      *  TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
@@ -129,4 +151,15 @@
                 && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
                 && request.showProvisioningUi == otherRequest.showProvisioningUi;
     }
+
+    /** Get inet6 address for all nodes given scope ID. */
+    public static Inet6Address getAllNodesForScopeId(int scopeId) {
+        try {
+            return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
+        } catch (UnknownHostException uhe) {
+            Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
+                    + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
+            return null;
+        }
+    }
 }
diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp
index ed69b7d..02bab9b 100644
--- a/packages/Tethering/tests/integration/Android.bp
+++ b/packages/Tethering/tests/integration/Android.bp
@@ -22,7 +22,6 @@
     static_libs: [
         "NetworkStackApiStableLib",
         "androidx.test.rules",
-        "frameworks-base-testutils",
         "mockito-target-extended-minus-junit4",
         "net-tests-utils",
         "testables",
diff --git a/packages/Tethering/tests/privileged/Android.bp b/packages/Tethering/tests/privileged/Android.bp
index a0fb246..9217345 100644
--- a/packages/Tethering/tests/privileged/Android.bp
+++ b/packages/Tethering/tests/privileged/Android.bp
@@ -14,8 +14,22 @@
 // limitations under the License.
 //
 
+java_defaults {
+    name: "TetheringPrivilegedTestsJniDefaults",
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+        "libtetherutilsjni",
+    ],
+    jni_uses_sdk_apis: true,
+    visibility: ["//visibility:private"],
+}
+
 android_test {
     name: "TetheringPrivilegedTests",
+    defaults: [
+        "TetheringPrivilegedTestsJniDefaults",
+    ],
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
@@ -23,8 +37,13 @@
     certificate: "networkstack",
     platform_apis: true,
     test_suites: [
-        "general-tests",
+        "device-tests",
         "mts",
     ],
+    static_libs: [
+        "androidx.test.rules",
+        "net-tests-utils",
+        "TetheringApiCurrentLib",
+    ],
     compile_multilib: "both",
 }
diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
new file mode 100644
index 0000000..747d3e8
--- /dev/null
+++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+
+import static com.android.internal.util.BitUtils.uint16;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.INetd;
+import android.net.InetAddresses;
+import android.net.MacAddress;
+import android.net.TestNetworkInterface;
+import android.net.TestNetworkManager;
+import android.net.util.InterfaceParams;
+import android.net.util.IpUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.TapPacketReader;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DadProxyTest {
+    private static final int DATA_BUFFER_LEN = 4096;
+    private static final int PACKET_TIMEOUT_MS = 5_000;
+
+    // TODO: make NetworkStackConstants accessible to this test and use the constant from there.
+    private static final int ETHER_SRC_ADDR_OFFSET = 6;
+
+    private DadProxy mProxy;
+    TestNetworkInterface mUpstreamTestIface, mTetheredTestIface;
+    private InterfaceParams mUpstreamParams, mTetheredParams;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+    private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
+    private FileDescriptor mUpstreamTapFd, mTetheredTapFd;
+
+    private static INetd sNetd;
+
+    @BeforeClass
+    public static void setupOnce() {
+        System.loadLibrary("tetherutilsjni");
+
+        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        final IBinder netdIBinder =
+                (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
+        sNetd = INetd.Stub.asInterface(netdIBinder);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mHandlerThread = new HandlerThread(getClass().getSimpleName());
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+
+        setupTapInterfaces();
+
+        // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
+        if (Looper.myLooper() == null) Looper.prepare();
+
+        DadProxy mProxy = setupProxy();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mHandlerThread != null) {
+            mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket
+            mHandler.post(mTetheredPacketReader::stop); // Also closes the socket
+            mUpstreamTapFd = null;
+            mTetheredTapFd = null;
+            mHandlerThread.quitSafely();
+        }
+
+        if (mTetheredParams != null) {
+            sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+        }
+        if (mUpstreamParams != null) {
+            sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+        }
+
+        if (mUpstreamTestIface != null) {
+            try {
+                Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor());
+            } catch (ErrnoException e) { }
+        }
+
+        if (mTetheredTestIface != null) {
+            try {
+                Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor());
+            } catch (ErrnoException e) { }
+        }
+    }
+
+    private TestNetworkInterface setupTapInterface() {
+        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        AtomicReference<TestNetworkInterface> iface = new AtomicReference<>();
+
+        inst.getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService(
+                    Context.TEST_NETWORK_SERVICE);
+            iface.set(tnm.createTapInterface());
+        } finally {
+            inst.getUiAutomation().dropShellPermissionIdentity();
+        }
+
+        return iface.get();
+    }
+
+    private void setupTapInterfaces() {
+        // Create upstream test iface.
+        mUpstreamTestIface = setupTapInterface();
+        mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName());
+        assertNotNull(mUpstreamParams);
+        mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor();
+        mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd,
+                                                    DATA_BUFFER_LEN);
+        mHandler.post(mUpstreamPacketReader::start);
+
+        // Create tethered test iface.
+        mTetheredTestIface = setupTapInterface();
+        mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName());
+        assertNotNull(mTetheredParams);
+        mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor();
+        mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd,
+                                                    DATA_BUFFER_LEN);
+        mHandler.post(mTetheredPacketReader::start);
+    }
+
+    private static final int IPV6_HEADER_LEN = 40;
+    private static final int ETH_HEADER_LEN = 14;
+    private static final int ICMPV6_NA_NS_LEN = 24;
+    private static final int LL_TARGET_OPTION_LEN = 8;
+    private static final int ICMPV6_CHECKSUM_OFFSET = 2;
+    private static final int ETHER_TYPE_IPV6 = 0x86dd;
+
+    // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+    private static int checksumFold(int sum) {
+        while (sum > 0xffff) {
+            sum = (sum >> 16) + (sum & 0xffff);
+        }
+        return sum;
+    }
+
+    // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+    private static short checksumAdjust(short checksum, short oldWord, short newWord) {
+        checksum = (short) ~checksum;
+        int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
+        return (short) ~tempSum;
+    }
+
+    // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+    private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
+            int transportLen) {
+        // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
+        // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
+        // checksum adjustment  for the change in the next header byte.
+        short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
+        return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
+    }
+
+    private static ByteBuffer createDadPacket(int type) {
+        // Refer to buildArpPacket()
+        int icmpLen = ICMPV6_NA_NS_LEN
+                + (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT
+                ? LL_TARGET_OPTION_LEN : 0);
+        final ByteBuffer buf = ByteBuffer.allocate(icmpLen + IPV6_HEADER_LEN + ETH_HEADER_LEN);
+
+        // Ethernet header.
+        final MacAddress srcMac = MacAddress.fromString("33:33:ff:66:77:88");
+        buf.put(srcMac.toByteArray());
+        final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06");
+        buf.put(dstMac.toByteArray());
+        buf.putShort((short) ETHER_TYPE_IPV6);
+
+        // IPv6 header
+        byte[] version = {(byte) 0x60, 0x00, 0x00, 0x00};
+        buf.put(version);                                           // Version
+        buf.putShort((byte) icmpLen);                               // Length
+        buf.put((byte) IPPROTO_ICMPV6);                             // Next header
+        buf.put((byte) 0xff);                                       // Hop limit
+
+        final byte[] target =
+            InetAddresses.parseNumericAddress("fe80::1122:3344:5566:7788").getAddress();
+        final byte[] src;
+        final byte[] dst;
+        if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION) {
+            src = InetAddresses.parseNumericAddress("::").getAddress();
+            dst = InetAddresses.parseNumericAddress("ff02::1:ff66:7788").getAddress();
+        } else {
+            src = target;
+            dst = TetheringUtils.ALL_NODES;
+        }
+        buf.put(src);
+        buf.put(dst);
+
+        // ICMPv6 Header
+        buf.put((byte) type);                                       // Type
+        buf.put((byte) 0x00);                                       // Code
+        buf.putShort((short) 0);                                    // Checksum
+        buf.putInt(0);                                              // Reserved
+        buf.put(target);
+
+        if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+            //NA packet has LL target address
+            //ICMPv6 Option
+            buf.put((byte) 0x02);                                   // Type
+            buf.put((byte) 0x01);                                   // Length
+            byte[] ll_target = MacAddress.fromString("01:02:03:04:05:06").toByteArray();
+            buf.put(ll_target);
+        }
+
+        // Populate checksum field
+        final int transportOffset = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+        final short checksum = icmpv6Checksum(buf, ETH_HEADER_LEN, transportOffset, icmpLen);
+        buf.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum);
+
+        buf.flip();
+        return buf;
+    }
+
+    private DadProxy setupProxy() throws Exception {
+        DadProxy proxy = new DadProxy(mHandler, mTetheredParams);
+        mHandler.post(() -> proxy.setUpstreamIface(mUpstreamParams));
+
+        // Upstream iface is added to local network to simplify test case.
+        // Otherwise the test needs to create and destroy a network for the upstream iface.
+        sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+        sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+
+        return proxy;
+    }
+
+    // TODO: change to assert.
+    private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) {
+        byte[] p;
+
+        while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) {
+            final ByteBuffer buffer = ByteBuffer.wrap(p);
+
+            if (buffer.compareTo(packet) == 0) return true;
+        }
+        return false;
+    }
+
+    private void updateDstMac(ByteBuffer buf, MacAddress mac) {
+        buf.put(mac.toByteArray());
+        buf.rewind();
+    }
+    private void updateSrcMac(ByteBuffer buf, InterfaceParams ifaceParams) {
+        buf.position(ETHER_SRC_ADDR_OFFSET);
+        buf.put(ifaceParams.macAddr.toByteArray());
+        buf.rewind();
+    }
+
+    @Test
+    public void testNaForwardingFromUpstreamToTether() throws Exception {
+        ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+        mUpstreamPacketReader.sendResponse(na);
+        updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+        updateSrcMac(na, mTetheredParams);
+        assertTrue(waitForPacket(na, mTetheredPacketReader));
+    }
+
+    @Test
+    // TODO: remove test once DAD works in both directions.
+    public void testNaForwardingFromTetherToUpstream() throws Exception {
+        ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+        mTetheredPacketReader.sendResponse(na);
+        updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+        updateSrcMac(na, mTetheredParams);
+        assertFalse(waitForPacket(na, mUpstreamPacketReader));
+    }
+
+    @Test
+    public void testNsForwardingFromTetherToUpstream() throws Exception {
+        ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+        mTetheredPacketReader.sendResponse(ns);
+        updateSrcMac(ns, mUpstreamParams);
+        assertTrue(waitForPacket(ns, mUpstreamPacketReader));
+    }
+
+    @Test
+    // TODO: remove test once DAD works in both directions.
+    public void testNsForwardingFromUpstreamToTether() throws Exception {
+        ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+        mUpstreamPacketReader.sendResponse(ns);
+        updateSrcMac(ns, mUpstreamParams);
+        assertFalse(waitForPacket(ns, mTetheredPacketReader));
+    }
+}
diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt
index ec2d2b0..7ed8963 100644
--- a/packages/Tethering/tests/unit/jarjar-rules.txt
+++ b/packages/Tethering/tests/unit/jarjar-rules.txt
@@ -9,3 +9,8 @@
 rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
 
 rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
+
+# TODO: either stop using frameworks-base-testutils or remove the unit test classes it contains.
+# TestableLooper from "testables" can be used instead of TestLooper from frameworks-base-testutils.
+zap android.os.test.TestLooperTest*
+zap com.android.test.filters.SelectTestTests*
\ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3b72b5b..1a976ad 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -86,6 +86,7 @@
 import android.net.util.InterfaceSet;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
+import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
@@ -100,8 +101,12 @@
 import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
 import com.android.networkstack.tethering.PrivateAddressCoordinator;
 import com.android.networkstack.tethering.TetheringConfiguration;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -120,6 +125,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IpServerTest {
+    @Rule
+    public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
     private static final String IFACE_NAME = "testnet1";
     private static final String UPSTREAM_IFACE = "upstream0";
     private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -132,6 +140,11 @@
 
     private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
             IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+    private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams(
+            UPSTREAM_IFACE, UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+    private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
+            UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS,
+            1500 /* defaultMtu */);
 
     private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
 
@@ -142,6 +155,7 @@
     @Mock private IpServer.Callback mCallback;
     @Mock private SharedLog mSharedLog;
     @Mock private IDhcpServer mDhcpServer;
+    @Mock private DadProxy mDadProxy;
     @Mock private RouterAdvertisementDaemon mRaDaemon;
     @Mock private IpNeighborMonitor mIpNeighborMonitor;
     @Mock private IpServer.Dependencies mDependencies;
@@ -165,8 +179,11 @@
 
     private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
             boolean usingBpfOffload) throws Exception {
+        when(mDependencies.getDadProxy(any(), any())).thenReturn(mDadProxy);
         when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
         when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+        when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
+        when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
 
         when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
         when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
@@ -1103,4 +1120,78 @@
         }
         return true;
     }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void dadProxyUpdates() throws Exception {
+        InOrder inOrder = inOrder(mDadProxy);
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+        inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+        // Add an upstream without IPv6.
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+        // Add IPv6 to the upstream.
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(UPSTREAM_IFACE);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+        // Change upstream.
+        // New linkproperties is needed, otherwise changing the iface has no impact.
+        LinkProperties lp2 = new LinkProperties();
+        lp2.setInterfaceName(UPSTREAM_IFACE2);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS2);
+
+        // Lose IPv6 on the upstream...
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE2, null, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+        // ... and regain it on a different upstream.
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+        // Lose upstream.
+        dispatchTetherConnectionChanged(null, null, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+        // Regain upstream.
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+        inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+        // Stop tethering.
+        mIpServer.stop();
+        mLooper.dispatchAll();
+    }
+
+    private void checkDadProxyEnabled(boolean expectEnabled) throws Exception {
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+        InOrder inOrder = inOrder(mDadProxy);
+        // Add IPv6 to the upstream.
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(UPSTREAM_IFACE);
+        if (expectEnabled) {
+            inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+        } else {
+            inOrder.verifyNoMoreInteractions();
+        }
+        // Stop tethering.
+        mIpServer.stop();
+        mLooper.dispatchAll();
+        if (expectEnabled) {
+            inOrder.verify(mDadProxy).stop();
+        }
+        else {
+            verify(mDependencies, never()).getDadProxy(any(), any());
+        }
+    }
+    @Test @IgnoreAfter(Build.VERSION_CODES.R)
+    public void testDadProxyUpdates_DisabledUpToR() throws Exception {
+        checkDadProxyEnabled(false);
+    }
+    @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+    public void testDadProxyUpdates_EnabledAfterR() throws Exception {
+        checkDadProxyEnabled(true);
+    }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 1fe3840..df57020 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -110,6 +110,7 @@
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpServer;
+import android.net.ip.DadProxy;
 import android.net.ip.IpNeighborMonitor;
 import android.net.ip.IpServer;
 import android.net.ip.RouterAdvertisementDaemon;
@@ -196,6 +197,7 @@
     @Mock private CarrierConfigManager mCarrierConfigManager;
     @Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     @Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+    @Mock private DadProxy mDadProxy;
     @Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
     @Mock private IpNeighborMonitor mIpNeighborMonitor;
     @Mock private IDhcpServer mDhcpServer;
@@ -280,6 +282,12 @@
 
     public class MockIpServerDependencies extends IpServer.Dependencies {
         @Override
+        public DadProxy getDadProxy(
+                Handler handler, InterfaceParams ifParams) {
+            return mDadProxy;
+        }
+
+        @Override
         public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
                 InterfaceParams ifParams) {
             return mRouterAdvertisementDaemon;
@@ -832,6 +840,7 @@
         verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         sendIPv6TetherUpdates(upstreamState);
+        verify(mDadProxy, never()).setUpstreamIface(notNull());
         verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
         verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
                 any(), any());
@@ -858,6 +867,8 @@
         verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         sendIPv6TetherUpdates(upstreamState);
+        // TODO: add interfaceParams to compare in verify.
+        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
@@ -874,6 +885,7 @@
                 any(), any());
 
         sendIPv6TetherUpdates(upstreamState);
+        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
@@ -891,6 +903,7 @@
         verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
 
         sendIPv6TetherUpdates(upstreamState);
+        verify(mDadProxy, times(1)).setUpstreamIface(notNull());
         verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
         verify(mNetd, times(1)).tetherApplyDnsInterfaces();
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9495fb5..ff79469 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -730,7 +730,8 @@
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
                 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
-                case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
+                case WindowManager.LayoutParams.TYPE_SCREENSHOT:
+                case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY: {
                     return AccessibilityWindowInfo.TYPE_SYSTEM;
                 }
 
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 8099f8f..e67b9d8 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -2,8 +2,7 @@
 per-file ConnectivityService.java,NetworkManagementService.java,NsdService.java = codewiz@google.com, ek@google.com, jchalard@google.com, junyulai@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
 
 # Vibrator / Threads
-per-file VibratorService.java, DisplayThread.java = michaelwr@google.com
-per-file VibratorService.java, DisplayThread.java = ogunwale@google.com
+per-file VibratorManagerService.java, VibratorService.java, DisplayThread.java = michaelwr@google.com, ogunwale@google.com
 
 # Zram writeback
 per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 829fca6..9fc8f0b 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -454,10 +454,14 @@
         public boolean mayObservePackage(String packageName) {
             PackageManager pm = mContext.getPackageManager();
             try {
-                // A package is a Mainline module if this is non-null
+                // A package is a module if this is non-null
                 if (pm.getModuleInfo(packageName, 0) != null) {
                     return true;
                 }
+            } catch (PackageManager.NameNotFoundException ignore) {
+            }
+
+            try {
                 ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
                 return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
             } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/VibratorManagerService.java b/services/core/java/com/android/server/VibratorManagerService.java
new file mode 100644
index 0000000..2f35da7
--- /dev/null
+++ b/services/core/java/com/android/server/VibratorManagerService.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IVibratorManagerService;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/** System implementation of {@link IVibratorManagerService}. */
+public class VibratorManagerService extends IVibratorManagerService.Stub {
+    private static final String TAG = "VibratorManagerService";
+    private static final boolean DEBUG = false;
+
+    private final Context mContext;
+    private final NativeWrapper mNativeWrapper;
+    private final int[] mVibratorIds;
+
+    static native long nativeInit();
+
+    static native long nativeGetFinalizer();
+
+    static native int[] nativeGetVibratorIds(long nativeServicePtr);
+
+    VibratorManagerService(Context context) {
+        this(context, new Injector());
+    }
+
+    @VisibleForTesting
+    VibratorManagerService(Context context, Injector injector) {
+        mContext = context;
+        mNativeWrapper = injector.getNativeWrapper();
+
+        mNativeWrapper.init();
+
+        int[] vibratorIds = mNativeWrapper.getVibratorIds();
+        mVibratorIds = vibratorIds == null ? new int[0] : vibratorIds;
+    }
+
+    @Override // Binder call
+    public int[] getVibratorIds() {
+        return Arrays.copyOf(mVibratorIds, mVibratorIds.length);
+    }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, ShellCallback cb, ResultReceiver resultReceiver) {
+        new VibratorManagerShellCommand(this).exec(this, in, out, err, args, cb, resultReceiver);
+    }
+
+    /** Point of injection for test dependencies */
+    @VisibleForTesting
+    static class Injector {
+
+        NativeWrapper getNativeWrapper() {
+            return new NativeWrapper();
+        }
+    }
+
+    /** Wrapper around the static-native methods of {@link VibratorManagerService} for tests. */
+    @VisibleForTesting
+    public static class NativeWrapper {
+
+        private long mNativeServicePtr = 0;
+
+        /** Returns native pointer to newly created controller and connects with HAL service. */
+        public void init() {
+            mNativeServicePtr = VibratorManagerService.nativeInit();
+            long finalizerPtr = VibratorManagerService.nativeGetFinalizer();
+
+            if (finalizerPtr != 0) {
+                NativeAllocationRegistry registry =
+                        NativeAllocationRegistry.createMalloced(
+                                VibratorManagerService.class.getClassLoader(), finalizerPtr);
+                registry.registerNativeAllocation(this, mNativeServicePtr);
+            }
+        }
+
+        /** Returns vibrator ids. */
+        public int[] getVibratorIds() {
+            return VibratorManagerService.nativeGetVibratorIds(mNativeServicePtr);
+        }
+    }
+
+    /** Provides limited functionality from {@link VibratorManagerService} as shell commands. */
+    private final class VibratorManagerShellCommand extends ShellCommand {
+
+        private final IBinder mToken;
+
+        private VibratorManagerShellCommand(IBinder token) {
+            mToken = token;
+        }
+
+        @Override
+        public int onCommand(String cmd) {
+            if ("list".equals(cmd)) {
+                return runListVibrators();
+            }
+            return handleDefaultCommands(cmd);
+        }
+
+        private int runListVibrators() {
+            try (PrintWriter pw = getOutPrintWriter();) {
+                if (mVibratorIds.length == 0) {
+                    pw.println("No vibrator found");
+                } else {
+                    for (int id : mVibratorIds) {
+                        pw.println(id);
+                    }
+                }
+                pw.println("");
+                return 0;
+            }
+        }
+
+        @Override
+        public void onHelp() {
+            try (PrintWriter pw = getOutPrintWriter();) {
+                pw.println("Vibrator Manager commands:");
+                pw.println("  help");
+                pw.println("    Prints this help text.");
+                pw.println("");
+                pw.println("  list");
+                pw.println("    Prints the id of device vibrators. This do not include any ");
+                pw.println("    connected input device.");
+                pw.println("");
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 687af10..cb6f616 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -385,15 +385,7 @@
         mNativeWrapper = injector.getNativeWrapper();
         mH = injector.createHandler(Looper.myLooper());
 
-        long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete);
-        long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
-
-        if (finalizerPtr != 0) {
-            NativeAllocationRegistry registry =
-                    NativeAllocationRegistry.createMalloced(
-                            VibratorService.class.getClassLoader(), finalizerPtr);
-            registry.registerNativeAllocation(this, nativeServicePtr);
-        }
+        mNativeWrapper.vibratorInit(this::onVibrationComplete);
 
         // Reset the hardware to a default state, in case this is a runtime
         // restart instead of a fresh boot.
@@ -1746,18 +1738,17 @@
             return VibratorService.vibratorExists(mNativeServicePtr);
         }
 
-        /**
-         * Returns native pointer to newly created controller and initializes connection to vibrator
-         * HAL service.
-         */
-        public long vibratorInit(OnCompleteListener listener) {
+        /** Initializes connection to vibrator HAL service. */
+        public void vibratorInit(OnCompleteListener listener) {
             mNativeServicePtr = VibratorService.vibratorInit(listener);
-            return mNativeServicePtr;
-        }
+            long finalizerPtr = VibratorService.vibratorGetFinalizer();
 
-        /** Returns pointer to native finalizer function to be called by GC. */
-        public long vibratorGetFinalizer() {
-            return VibratorService.vibratorGetFinalizer();
+            if (finalizerPtr != 0) {
+                NativeAllocationRegistry registry =
+                        NativeAllocationRegistry.createMalloced(
+                                VibratorService.class.getClassLoader(), finalizerPtr);
+                registry.registerNativeAllocation(this, mNativeServicePtr);
+            }
         }
 
         /** Turns vibrator on for given time. */
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c0f6011..91a3fb0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -478,15 +478,15 @@
     }
 
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
-            int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
-            String callingPackage, @Nullable String callingFeatureId, final int userId)
+            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
+            @Nullable String callingFeatureId, final int userId)
             throws TransactionTooLargeException {
         return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
-                hideFgNotification, callingPackage, callingFeatureId, userId, false, null);
+                callingPackage, callingFeatureId, userId, false, null);
     }
 
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
-            int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
+            int callingPid, int callingUid, boolean fgRequired,
             String callingPackage, @Nullable String callingFeatureId, final int userId,
             boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
             throws TransactionTooLargeException {
@@ -653,7 +653,6 @@
         r.startRequested = true;
         r.delayedStop = false;
         r.fgRequired = fgRequired;
-        r.hideFgNotification = hideFgNotification;
         r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                 service, neededGrants, callingUid));
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bd7d3de..65334fd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1177,10 +1177,6 @@
 
     final Injector mInjector;
 
-    /** The package verifier app. */
-    private String mPackageVerifier;
-    private int mPackageVerifierUid = UserHandle.USER_NULL;
-
     static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
         static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
@@ -1809,18 +1805,6 @@
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
                 mService.mBatteryStatsService.systemServicesReady();
                 mService.mServices.systemServicesReady();
-                mService.mPackageVerifier = ArrayUtils.firstOrNull(
-                        LocalServices.getService(PackageManagerInternal.class).getKnownPackageNames(
-                                PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM));
-                if (mService.mPackageVerifier != null) {
-                    try {
-                        mService.mPackageVerifierUid =
-                                getContext().getPackageManager().getPackageUid(
-                                        mService.mPackageVerifier, UserHandle.USER_SYSTEM);
-                    } catch (NameNotFoundException e) {
-                        Slog.wtf(TAG, "Package manager couldn't get package verifier uid", e);
-                    }
-                }
             } else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
                 mService.startBroadcastObservers();
             } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
@@ -11233,10 +11217,10 @@
             }
             long kernelUsed = memInfo.getKernelUsedSizeKb();
             final long ionHeap = Debug.getIonHeapsSizeKb();
-            if (ionHeap > 0) {
+            final long ionPool = Debug.getIonPoolsSizeKb();
+            if (ionHeap >= 0 && ionPool >= 0) {
                 final long ionMapped = Debug.getIonMappedSizeKb();
                 final long ionUnmapped = ionHeap - ionMapped;
-                final long ionPool = Debug.getIonPoolsSizeKb();
                 pw.print("      ION: ");
                         pw.print(stringifyKBSize(ionHeap + ionPool));
                         pw.print(" (");
@@ -12033,10 +12017,10 @@
         memInfoBuilder.append("\n");
         long kernelUsed = memInfo.getKernelUsedSizeKb();
         final long ionHeap = Debug.getIonHeapsSizeKb();
-        if (ionHeap > 0) {
+        final long ionPool = Debug.getIonPoolsSizeKb();
+        if (ionHeap >= 0 && ionPool >= 0) {
             final long ionMapped = Debug.getIonMappedSizeKb();
             final long ionUnmapped = ionHeap - ionMapped;
-            final long ionPool = Debug.getIonPoolsSizeKb();
             memInfoBuilder.append("       ION: ");
             memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
             memInfoBuilder.append("\n");
@@ -12359,8 +12343,8 @@
 
     @Override
     public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType, boolean requireForeground, boolean hideForegroundNotification,
-            String callingPackage, String callingFeatureId, int userId)
+            String resolvedType, boolean requireForeground, String callingPackage,
+            String callingFeatureId, int userId)
             throws TransactionTooLargeException {
         enforceNotIsolatedCaller("startService");
         // Refuse possible leaked file descriptors
@@ -12372,27 +12356,17 @@
             throw new IllegalArgumentException("callingPackage cannot be null");
         }
 
-        final int callingUid = Binder.getCallingUid();
-        if (requireForeground && hideForegroundNotification) {
-            if (!UserHandle.isSameApp(callingUid, mPackageVerifierUid)
-                    || !callingPackage.equals(mPackageVerifier)) {
-                throw new IllegalArgumentException(
-                        "Only the package verifier can hide its foreground service notification");
-            }
-            Slog.i(TAG, "Foreground service notification hiding requested by " + callingPackage);
-        }
-
         if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                 "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
+            final int callingUid = Binder.getCallingUid();
             final long origId = Binder.clearCallingIdentity();
             ComponentName res;
             try {
                 res = mServices.startServiceLocked(caller, service,
                         resolvedType, callingPid, callingUid,
-                        requireForeground, hideForegroundNotification,
-                        callingPackage, callingFeatureId, userId);
+                        requireForeground, callingPackage, callingFeatureId, userId);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -16305,7 +16279,7 @@
                 ComponentName res;
                 try {
                     res = mServices.startServiceLocked(null, service,
-                            resolvedType, -1, uid, fgRequired, false, callingPackage,
+                            resolvedType, -1, uid, fgRequired, callingPackage,
                             callingFeatureId, userId, allowBackgroundActivityStarts,
                             backgroundActivityStartsToken);
                 } finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 1119728..d346430 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -655,7 +655,7 @@
         pw.println("Starting service: " + intent);
         pw.flush();
         ComponentName cn = mInterface.startService(null, intent, intent.getType(),
-                asForeground, false, SHELL_PACKAGE_NAME, null, mUserId);
+                asForeground, SHELL_PACKAGE_NAME, null, mUserId);
         if (cn == null) {
             err.println("Error: Not found; no service started.");
             return -1;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index a7d8ca4..4cdf661 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -105,7 +105,6 @@
     boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT?
     boolean delayed;        // are we waiting to start this service in the background?
     boolean fgRequired;     // is the service required to go foreground after starting?
-    boolean hideFgNotification; // Hide the fg service notification
     boolean fgWaiting;      // is a timeout for going foreground already scheduled?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
@@ -886,9 +885,6 @@
     }
 
     public void postNotification() {
-        if (hideFgNotification) {
-            return;
-        }
         final int appUid = appInfo.uid;
         final int appPid = app.pid;
         if (foregroundId != 0 && foregroundNoti != null) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index ded0f9a3..8de31d9 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -450,6 +450,7 @@
     }
 
     @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("BtHelper.this")
     private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
         AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
         client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
diff --git a/services/core/java/com/android/server/biometrics/SensorConfig.java b/services/core/java/com/android/server/biometrics/SensorConfig.java
index 7743f1c..a83f67a 100644
--- a/services/core/java/com/android/server/biometrics/SensorConfig.java
+++ b/services/core/java/com/android/server/biometrics/SensorConfig.java
@@ -16,13 +16,15 @@
 
 package com.android.server.biometrics;
 
+import android.hardware.biometrics.BiometricManager;
+
 /**
  * Parsed sensor config. See core/res/res/values/config.xml config_biometric_sensors
  */
 public class SensorConfig {
     public final int id;
     final int modality;
-    final int strength;
+    @BiometricManager.Authenticators.Types public final int strength;
 
     public SensorConfig(String config) {
         String[] elems = config.split(":");
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 88fd444..c300169 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -48,6 +48,7 @@
 import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorProperties;
 import android.os.Binder;
 import android.os.Build;
 import android.os.RemoteException;
@@ -444,4 +445,22 @@
         }
         return false;
     }
+
+    /**
+     * Converts from {@link BiometricManager.Authenticators} biometric strength to the internal
+     * {@link SensorProperties} strength.
+     */
+    public static @SensorProperties.Strength int authenticatorStrengthToPropertyStrength(
+            @BiometricManager.Authenticators.Types int strength) {
+        switch (strength) {
+            case BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE:
+                return SensorProperties.STRENGTH_CONVENIENCE;
+            case BiometricManager.Authenticators.BIOMETRIC_WEAK:
+                return SensorProperties.STRENGTH_WEAK;
+            case BiometricManager.Authenticators.BIOMETRIC_STRONG:
+                return SensorProperties.STRENGTH_STRONG;
+            default:
+                throw new IllegalArgumentException("Unknown strength: " + strength);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
index 1613d3b..6e6ec74 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
@@ -26,6 +26,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
 import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
@@ -279,6 +280,7 @@
     };
 
     Face10(@NonNull Context context, int sensorId,
+            @BiometricManager.Authenticators.Types int strength,
             @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
         final boolean supportsSelfIllumination = context.getResources()
                 .getBoolean(R.bool.config_faceAuthSupportsSelfIllumination);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index bbee6cd..3318bcb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -34,7 +34,7 @@
     public FaceAuthenticator(IFaceService faceService, SensorConfig config)
             throws RemoteException {
         mFaceService = faceService;
-        mFaceService.initializeConfiguration(config.id);
+        mFaceService.initializeConfiguration(config.id, config.strength);
     }
 
     @Override
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 c6664f4..82dc0d0 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
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
@@ -308,9 +309,10 @@
         }
 
         @Override // Binder call
-        public void initializeConfiguration(int sensorId) {
+        public void initializeConfiguration(int sensorId,
+                @BiometricManager.Authenticators.Types int strength) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-            mFace10 = new Face10(getContext(), sensorId, mLockoutResetDispatcher);
+            mFace10 = new Face10(getContext(), sensorId, strength, mLockoutResetDispatcher);
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
index 7e62329..507b5dd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
@@ -296,6 +297,7 @@
 
     Fingerprint21(@NonNull Context context, @NonNull BiometricScheduler scheduler,
             @NonNull Handler handler, int sensorId,
+            @BiometricManager.Authenticators.Types int strength,
             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
             @NonNull HalResultController controller) {
         mContext = context;
@@ -335,25 +337,27 @@
         }
 
         final @FingerprintSensorProperties.SensorType int sensorType =
-                isUdfps ? FingerprintSensorProperties.TYPE_UDFPS
+                isUdfps ? FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
                         : FingerprintSensorProperties.TYPE_REAR;
         // resetLockout is controlled by the framework, so hardwareAuthToken is not required
         final boolean resetLockoutRequiresHardwareAuthToken = false;
-        final int maxTemplatesAllowed = mContext.getResources()
+        final int maxEnrollmentsPerUser = mContext.getResources()
                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
-        mSensorProperties = new FingerprintSensorProperties(sensorId, sensorType,
-                resetLockoutRequiresHardwareAuthToken, maxTemplatesAllowed);
+
+        mSensorProperties = new FingerprintSensorProperties(sensorId,
+                Utils.authenticatorStrengthToPropertyStrength(strength), maxEnrollmentsPerUser,
+                sensorType, resetLockoutRequiresHardwareAuthToken);
     }
 
-    static Fingerprint21 newInstance(@NonNull Context context, int sensorId,
+    static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength,
             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
             @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
         final Handler handler = new Handler(Looper.getMainLooper());
         final BiometricScheduler scheduler =
                 new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
         final HalResultController controller = new HalResultController(context, handler, scheduler);
-        return new Fingerprint21(context, scheduler, handler, sensorId, lockoutResetDispatcher,
-                controller);
+        return new Fingerprint21(context, scheduler, handler, sensorId, strength,
+                lockoutResetDispatcher, controller);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java
index 7cab2b8..044dbe9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java
@@ -21,6 +21,7 @@
 import android.app.trust.TrustManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -36,6 +37,7 @@
 import android.util.SparseBooleanArray;
 
 import com.android.internal.R;
+import com.android.server.biometrics.Utils;
 import com.android.server.biometrics.sensors.AuthenticationConsumer;
 import com.android.server.biometrics.sensors.BiometricScheduler;
 import com.android.server.biometrics.sensors.ClientMonitor;
@@ -266,6 +268,7 @@
     }
 
     static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId,
+            @BiometricManager.Authenticators.Types int strength,
             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
             @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
         Slog.d(TAG, "Creating Fingerprint23Mock!");
@@ -275,7 +278,7 @@
                 new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
         final MockHalResultController controller =
                 new MockHalResultController(context, handler, scheduler);
-        return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId,
+        return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength,
                 lockoutResetDispatcher, controller);
     }
 
@@ -401,9 +404,10 @@
     private Fingerprint21UdfpsMock(@NonNull Context context,
             @NonNull TestableBiometricScheduler scheduler,
             @NonNull Handler handler, int sensorId,
+            @BiometricManager.Authenticators.Types int strength,
             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
             @NonNull MockHalResultController controller) {
-        super(context, scheduler, handler, sensorId, lockoutResetDispatcher, controller);
+        super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, controller);
         mScheduler = scheduler;
         mScheduler.init(this);
         mHandler = handler;
@@ -412,8 +416,9 @@
         final int maxTemplatesAllowed = mContext.getResources()
                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
         mSensorProperties = new FingerprintSensorProperties(sensorId,
-                FingerprintSensorProperties.TYPE_UDFPS, resetLockoutRequiresHardwareAuthToken,
-                maxTemplatesAllowed);
+                Utils.authenticatorStrengthToPropertyStrength(strength), maxTemplatesAllowed,
+                FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+                resetLockoutRequiresHardwareAuthToken);
         mMockHalResultController = controller;
         mUserHasTrust = new SparseBooleanArray();
         mTrustManager = context.getSystemService(TrustManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 21a46d5..5219df4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -34,7 +34,7 @@
     public FingerprintAuthenticator(IFingerprintService fingerprintService, SensorConfig config)
             throws RemoteException {
         mFingerprintService = fingerprintService;
-        mFingerprintService.initializeConfiguration(config.id);
+        mFingerprintService.initializeConfiguration(config.id, config.strength);
     }
 
     @Override
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 7c7da11..2f0e564 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
@@ -384,7 +384,7 @@
         }
 
         @Override // Binder call
-        public void initializeConfiguration(int sensorId) {
+        public void initializeConfiguration(int sensorId, int strength) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             if ((Build.IS_USERDEBUG || Build.IS_ENG)
@@ -393,9 +393,9 @@
                     Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
                     UserHandle.USER_CURRENT) != 0) {
                 mFingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
-                        mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+                        strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
             } else {
-                mFingerprint21 = Fingerprint21.newInstance(getContext(), sensorId,
+                mFingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
                         mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 1f0066a..01fa9e7 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -367,6 +367,13 @@
                     Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
                 }
             }
+            // Ignore the case when the network disconnects immediately after stop() has been
+            // called and the keepalive code is waiting for the response from the modem. This
+            // might happen when the caller listens for a lower-layer network disconnect
+            // callback and stop the keepalive at that time. But the stop() races with the
+            // stop() generated in ConnectivityService network disconnection code path.
+            if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return;
+
             // Store the reason of stopping, and report it after the keepalive is fully stopped.
             if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
                 throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
@@ -380,9 +387,6 @@
                     // e.g. invalid parameter.
                     cleanupStoppedKeepalive(mNai, mSlot);
                     break;
-                case STOPPING:
-                    // Keepalive is already in stopping state, ignore.
-                    return;
                 default:
                     mStartedState = STOPPING;
                     switch (mType) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 828591a..7c98c6c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -552,7 +552,7 @@
         try {
             InputChannel inputChannel = nativeCreateInputMonitor(
                     mPtr, displayId, true /*isGestureMonitor*/, inputChannelName);
-            InputMonitorHost host = new InputMonitorHost(inputChannel);
+            InputMonitorHost host = new InputMonitorHost(inputChannel.getToken());
             synchronized (mGestureMonitorPidsLock) {
                 mGestureMonitorPidsByToken.put(inputChannel.getToken(), pid);
             }
@@ -2434,21 +2434,20 @@
      * Interface for the system to handle request from InputMonitors.
      */
     private final class InputMonitorHost extends IInputMonitorHost.Stub {
-        private final InputChannel mInputChannel;
+        private final IBinder mToken;
 
-        InputMonitorHost(InputChannel channel) {
-            mInputChannel = channel;
+        InputMonitorHost(IBinder token) {
+            mToken = token;
         }
 
         @Override
         public void pilferPointers() {
-            nativePilferPointers(mPtr, mInputChannel.getToken());
+            nativePilferPointers(mPtr, mToken);
         }
 
         @Override
         public void dispose() {
-            nativeRemoveInputChannel(mPtr, mInputChannel.getToken());
-            mInputChannel.dispose();
+            nativeRemoveInputChannel(mPtr, mToken);
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index b9997e0..0a4d17f 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -259,7 +259,7 @@
             return "";
         }
         return String.join(COMPONENT_NAME_USER_ID_DELIM,
-                mComponentName.toString(),
+                mComponentName.flattenToString(),
                 String.valueOf(mUserId),
                 String.valueOf(mComponentType));
     }
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 5bbe490..4c1b700 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -75,6 +75,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
@@ -143,6 +144,9 @@
 
         private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
 
+        @GuardedBy("mListeners")
+        private boolean mIsWatchingPackageBroadcasts = false;
+
         private final ShortcutChangeHandler mShortcutChangeHandler;
 
         private final Handler mCallbackHandler;
@@ -281,7 +285,10 @@
          * Register a receiver to watch for package broadcasts
          */
         private void startWatchingPackageBroadcasts() {
-            mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
+            if (!mIsWatchingPackageBroadcasts) {
+                mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
+                mIsWatchingPackageBroadcasts = true;
+            }
         }
 
         /**
@@ -291,7 +298,10 @@
             if (DEBUG) {
                 Log.d(TAG, "Stopped watching for packages");
             }
-            mPackageMonitor.unregister();
+            if (mIsWatchingPackageBroadcasts) {
+                mPackageMonitor.unregister();
+                mIsWatchingPackageBroadcasts = false;
+            }
         }
 
         void checkCallbackCount() {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f52db5f..31ee597 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -618,6 +618,13 @@
             }
         }
 
+        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
+                && !isCalledBySystemOrShell(callingUid)
+                && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            throw new SecurityException(
+                    "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
+        }
+
         if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
             if (mBypassNextStagedInstallerCheck) {
                 mBypassNextStagedInstallerCheck = false;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 2a189c0..60737bf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -169,6 +169,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 
 public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private static final String TAG = "PackageInstallerSession";
@@ -689,7 +690,7 @@
                 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
 
         if (isDataLoaderInstallation()) {
-            if (isApexInstallation()) {
+            if (isApexSession()) {
                 throw new IllegalArgumentException(
                         "DataLoader installation of APEX modules is not allowed.");
             }
@@ -1576,7 +1577,7 @@
                         return false;
                     }
 
-                    if (isApexInstallation()) {
+                    if (isApexSession()) {
                         validateApexInstallLocked();
                     } else {
                         validateApkInstallLocked();
@@ -1733,7 +1734,7 @@
             try {
                 sealLocked();
 
-                if (isApexInstallation()) {
+                if (isApexSession()) {
                     // APEX installations rely on certain fields to be populated after reboot.
                     // E.g. mPackageName.
                     validateApexInstallLocked();
@@ -1809,7 +1810,7 @@
             return;
         }
 
-        if (isApexInstallation()) {
+        if (isApexSession()) {
             destroyInternal();
             dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                     "APEX packages can only be installed using staged sessions.", null);
@@ -1986,7 +1987,7 @@
 
         // TODO(b/136257624): Some logic in this if block probably belongs in
         //  makeInstallParams().
-        if (!params.isMultiPackage && !isApexInstallation()) {
+        if (!params.isMultiPackage && !isApexSession()) {
             Objects.requireNonNull(mPackageName);
             Objects.requireNonNull(mSigningDetails);
             Objects.requireNonNull(mResolvedBaseFile);
@@ -2215,10 +2216,34 @@
     /**
      * Returns true if the session is installing an APEX package.
      */
-    private boolean isApexInstallation() {
+    boolean isApexSession() {
         return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
     }
 
+    private boolean sessionContains(Predicate<PackageInstallerSession> filter) {
+        if (!isMultiPackage()) {
+            return filter.test(this);
+        }
+        final List<PackageInstallerSession> childSessions;
+        synchronized (mLock) {
+            childSessions = getChildSessionsLocked();
+        }
+        for (PackageInstallerSession child: childSessions) {
+            if (filter.test(child)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean containsApexSession() {
+        return sessionContains((s) -> s.isApexSession());
+    }
+
+    boolean containsApkSession() {
+        return sessionContains((s) -> !s.isApexSession());
+    }
+
     /**
      * Validate apex install.
      * <p>
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 697c31a..b451eaf1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -282,6 +282,7 @@
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.permission.IPermissionManager;
+import android.provider.ContactsContract;
 import android.provider.DeviceConfig;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -349,6 +350,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.Watchdog;
+import com.android.server.compat.CompatChange;
 import com.android.server.compat.PlatformCompat;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.Installer.InstallerException;
@@ -1849,7 +1851,6 @@
                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
                     synchronized (mLock) {
                         removeMessages(WRITE_PACKAGE_LIST);
-                        mPermissionManager.writeStateToPackageSettingsTEMP();
                         mSettings.writePackageListLPr(msg.arg1);
                     }
                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2127,11 +2128,21 @@
         final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
         final String packageName = res.name;
         final PackageSetting pkgSetting = succeeded ? getPackageSetting(packageName) : null;
-        if (succeeded && pkgSetting == null) {
+        final boolean removedBeforeUpdate = (pkgSetting == null)
+                || (pkgSetting.isSystem() && !pkgSetting.getPathString().equals(res.pkg.getPath()));
+        if (succeeded && removedBeforeUpdate) {
             Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
                     + "could be executed");
             res.returnCode = INSTALL_FAILED_PACKAGE_CHANGED;
             res.returnMsg = "Package was removed before install could complete.";
+
+            // Remove the update failed package's older resources safely now
+            InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+            if (args != null) {
+                synchronized (mInstallLock) {
+                    args.doPostDeleteLI(true);
+                }
+            }
             notifyInstallObserver(res, installObserver);
             return;
         }
@@ -2686,7 +2697,8 @@
                 (i, pm) ->
                         new Settings(Environment.getDataDirectory(),
                                 i.getPermissionManagerServiceInternal().getPermissionSettings(),
-                                RuntimePermissionsPersistence.createInstance(), lock),
+                                RuntimePermissionsPersistence.createInstance(),
+                                i.getPermissionManagerServiceInternal(), lock),
                 new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
                 new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
                 new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
@@ -2703,39 +2715,43 @@
         PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
         t.traceEnd(); // "create package manager"
 
-        injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
-                packageName -> {
-                    synchronized (m.mInstallLock) {
-                        final AndroidPackage pkg;
-                        final PackageSetting ps;
-                        final SharedUserSetting sharedUser;
-                        final String oldSeInfo;
-                        synchronized (m.mLock) {
-                            ps = m.mSettings.getPackageLPr(packageName);
-                            if (ps == null) {
-                                Slog.e(TAG, "Failed to find package setting " + packageName);
-                                return;
-                            }
-                            pkg = ps.pkg;
-                            sharedUser = ps.getSharedUser();
-                            oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
-                        }
-
-                        if (pkg == null) {
-                            Slog.e(TAG, "Failed to find package " + packageName);
-                            return;
-                        }
-                        final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
-                                m.mInjector.getCompatibility());
-
-                        if (!newSeInfo.equals(oldSeInfo)) {
-                            Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
-                                    + oldSeInfo + " to: " + newSeInfo);
-                            ps.getPkgState().setOverrideSeInfo(newSeInfo);
-                            m.prepareAppDataAfterInstallLIF(pkg);
-                        }
+        final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
+            synchronized (m.mInstallLock) {
+                final AndroidPackage pkg;
+                final PackageSetting ps;
+                final SharedUserSetting sharedUser;
+                final String oldSeInfo;
+                synchronized (m.mLock) {
+                    ps = m.mSettings.getPackageLPr(packageName);
+                    if (ps == null) {
+                        Slog.e(TAG, "Failed to find package setting " + packageName);
+                        return;
                     }
-                });
+                    pkg = ps.pkg;
+                    sharedUser = ps.getSharedUser();
+                    oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
+                }
+
+                if (pkg == null) {
+                    Slog.e(TAG, "Failed to find package " + packageName);
+                    return;
+                }
+                final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
+                        m.mInjector.getCompatibility());
+
+                if (!newSeInfo.equals(oldSeInfo)) {
+                    Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
+                            + oldSeInfo + " to: " + newSeInfo);
+                    ps.getPkgState().setOverrideSeInfo(newSeInfo);
+                    m.prepareAppDataAfterInstallLIF(pkg);
+                }
+            }
+        };
+
+        injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
+                selinuxChangeListener);
+        injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_R_CHANGES,
+                selinuxChangeListener);
 
         m.installWhitelistedSystemPackages();
         ServiceManager.addService("package", m);
@@ -4486,8 +4502,8 @@
         AndroidPackage p = ps.pkg;
         if (p != null) {
             // Compute GIDs only if requested
-            final int[] gids = (flags & PackageManager.GET_GIDS) == 0
-                    ? EMPTY_INT_ARRAY : mPermissionManager.getPackageGids(ps.name, userId);
+            final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
+                    : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
             // Compute granted permissions only if package has requested permissions
             final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
                     ? Collections.emptySet()
@@ -4962,13 +4978,13 @@
                 }
                 // TODO: Shouldn't this be checking for package installed state for userId and
                 // return null?
-                return mPermissionManager.getPackageGids(packageName, userId);
+                return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null && ps.isMatch(flags)
                         && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
-                    return mPermissionManager.getPackageGids(packageName, userId);
+                    return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
                 }
             }
         }
@@ -18983,7 +18999,7 @@
                     }
                     if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0)
                             && !isUpdatedSystemApp(deletedPs)) {
-                        mPermissionManager.removePermissionsStateTEMP(removedAppId);
+                        mPermissionManager.removeAppIdStateTEMP(removedAppId);
                     }
                     mPermissionManager.updatePermissions(deletedPs.name, null);
                     if (deletedPs.sharedUser != null) {
@@ -21242,7 +21258,8 @@
             // Prior to enabling the package, we need to decompress the APK(s) to the
             // data partition and then replace the version on the system partition.
             final AndroidPackage deletedPkg = pkgSetting.pkg;
-            final boolean isSystemStub = deletedPkg.isStub()
+            final boolean isSystemStub = (deletedPkg != null)
+                    && deletedPkg.isStub()
                     && deletedPkg.isSystem();
             if (isSystemStub
                     && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -21854,8 +21871,6 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
 
-        mPermissionManager.writeStateToPackageSettingsTEMP();
-
         DumpState dumpState = new DumpState();
         boolean fullPreferred = false;
         boolean checkin = false;
@@ -23734,7 +23749,6 @@
             mDirtyUsers.remove(userId);
             mUserNeedsBadging.delete(userId);
             mPermissionManager.onUserRemoved(userId);
-            mPermissionManager.writeStateToPackageSettingsTEMP();
             mSettings.removeUserLPw(userId);
             mPendingBroadcasts.remove(userId);
             mInstantAppRegistry.onUserRemovedLPw(userId);
@@ -25716,6 +25730,32 @@
         }
     }
 
+    @Override
+    public void grantImplicitAccess(int recipientUid, String visibleAuthority) {
+        // This API is exposed temporarily to only the contacts provider. (b/158688602)
+        final int callingUid = Binder.getCallingUid();
+        ProviderInfo contactsProvider = resolveContentProviderInternal(
+                        ContactsContract.AUTHORITY, 0, UserHandle.USER_SYSTEM);
+        if (contactsProvider == null || contactsProvider.applicationInfo == null
+                || !UserHandle.isSameApp(contactsProvider.applicationInfo.uid, callingUid)) {
+            throw new SecurityException(callingUid + " is not allow to call grantImplicitAccess");
+        }
+        final int userId = UserHandle.getUserId(recipientUid);
+        final long token = Binder.clearCallingIdentity();
+        final ProviderInfo providerInfo;
+        try {
+            providerInfo = resolveContentProvider(visibleAuthority, 0 /*flags*/, userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        if (providerInfo == null) {
+            return;
+        }
+        int visibleUid = providerInfo.applicationInfo.uid;
+        mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid),
+                visibleUid, false);
+    }
+
     boolean canHaveOatDir(String packageName) {
         synchronized (mLock) {
             AndroidPackage p = mPackages.get(packageName);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d77683e..afbf7d3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2323,7 +2323,8 @@
 
     private boolean isVendorApp(String pkg) {
         try {
-            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            final PackageInfo info = mInterface.getPackageInfo(
+                     pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
             return info != null && info.applicationInfo.isVendor();
         } catch (RemoteException e) {
             return false;
@@ -2332,7 +2333,8 @@
 
     private boolean isProductApp(String pkg) {
         try {
-            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            final PackageInfo info = mInterface.getPackageInfo(
+                    pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
             return info != null && info.applicationInfo.isProduct();
         } catch (RemoteException e) {
             return false;
@@ -2341,7 +2343,8 @@
 
     private boolean isSystemExtApp(String pkg) {
         try {
-            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            final PackageInfo info = mInterface.getPackageInfo(
+                    pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
             return info != null && info.applicationInfo.isSystemExt();
         } catch (RemoteException e) {
             return false;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 276f880..855a5ff5 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -28,7 +28,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.AppIdPermissionState;
 import com.android.server.pm.pkg.PackageStateUnserialized;
 
 import java.io.File;
@@ -215,7 +215,7 @@
     }
 
     @Override
-    public PermissionsState getPermissionsState() {
+    public AppIdPermissionState getPermissionsState() {
         return (sharedUser != null)
                 ? sharedUser.getPermissionsState()
                 : super.getPermissionsState();
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index fdd9636..c5fbfba 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -18,6 +18,7 @@
 
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.Signature;
 import android.os.Environment;
@@ -77,9 +78,21 @@
     private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
 
     /**
-     * This change gates apps access to untrusted_app_R-targetSDk SELinux domain. Allows opt-in
+     * Allows opt-in to the latest targetSdkVersion enforced changes without changing target SDK.
+     * Turning this change off for an app targeting the latest SDK is a no-op.
+     *
+     * <p>Has no effect for apps using shared user id.
+     *
+     * TODO(b/143539591): Update description with relevant SELINUX changes this opts in to.
+     */
+    @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+    @ChangeId
+    static final long SELINUX_LATEST_CHANGES = 143539591L;
+
+    /**
+     * This change gates apps access to untrusted_app_R-targetSDK SELinux domain. Allows opt-in
      * to R targetSdkVersion enforced changes without changing target SDK. Turning this change
-     * off for an app targeting R is a no-op.
+     * off for an app targeting S is a no-op.
      *
      * <p>Has no effect for apps using shared user id.
      *
@@ -87,7 +100,7 @@
      */
     @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
     @ChangeId
-    static final long SELINUX_LATEST_CHANGES = 143539591L;
+    static final long SELINUX_R_CHANGES = 168782947L;
 
     // Only initialize sMacPermissions once.
     static {
@@ -349,9 +362,11 @@
         if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
             return sharedUserSetting.seInfoTargetSdkVersion;
         }
-        if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES,
-                pkg.toAppInfoWithoutState())) {
-            return android.os.Build.VERSION_CODES.R;
+        final ApplicationInfo appInfo = pkg.toAppInfoWithoutState();
+        if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES, appInfo)) {
+            return android.os.Build.VERSION_CODES.S;
+        } else if (compatibility.isChangeEnabledInternal(SELINUX_R_CHANGES, appInfo)) {
+            return Math.max(android.os.Build.VERSION_CODES.R, pkg.getTargetSdkVersion());
         }
 
         return pkg.getTargetSdkVersion();
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 3e2ab05..c1258b1 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -19,23 +19,23 @@
 import android.content.pm.ApplicationInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.AppIdPermissionState;
 
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public abstract class SettingBase {
     int pkgFlags;
     int pkgPrivateFlags;
 
-    protected final PermissionsState mPermissionsState;
+    protected final AppIdPermissionState mPermissionsState;
 
     SettingBase(int pkgFlags, int pkgPrivateFlags) {
         setFlags(pkgFlags);
         setPrivateFlags(pkgPrivateFlags);
-        mPermissionsState = new PermissionsState();
+        mPermissionsState = new AppIdPermissionState();
     }
 
     SettingBase(SettingBase orig) {
-        mPermissionsState = new PermissionsState();
+        mPermissionsState = new AppIdPermissionState();
         doCopy(orig);
     }
 
@@ -49,7 +49,7 @@
         mPermissionsState.copyFrom(orig.mPermissionsState);
     }
 
-    public PermissionsState getPermissionsState() {
+    public AppIdPermissionState getPermissionsState() {
         return mPermissionsState;
     }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 9654307..bae36b2a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -79,6 +79,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.Pair;
@@ -106,10 +107,11 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.permission.AppIdPermissionState;
+import com.android.server.pm.permission.AppIdPermissionState.PermissionState;
 import com.android.server.pm.permission.BasePermission;
+import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.PermissionSettings;
-import com.android.server.pm.permission.PermissionsState;
-import com.android.server.pm.permission.PermissionsState.PermissionState;
 import com.android.server.utils.TimingsTraceAndSlog;
 
 import libcore.io.IoUtils;
@@ -416,9 +418,12 @@
     private final File mSystemDir;
 
     public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+
     /** Settings and other information about permissions */
     final PermissionSettings mPermissions;
 
+    private final LegacyPermissionDataProvider mPermissionDataProvider;
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public Settings(Map<String, PackageSetting> pkgSettings) {
         mLock = new Object();
@@ -426,6 +431,7 @@
         mSystemDir = null;
         mPermissions = null;
         mRuntimePermissionsPersistence = null;
+        mPermissionDataProvider = null;
         mSettingsFilename = null;
         mBackupSettingsFilename = null;
         mPackageListFilename = null;
@@ -434,12 +440,14 @@
         mKernelMappingFilename = null;
     }
 
-    Settings(File dataDir, PermissionSettings permission,
-            RuntimePermissionsPersistence runtimePermissionsPersistence, Object lock) {
+    Settings(File dataDir, PermissionSettings permissionSettings,
+            RuntimePermissionsPersistence runtimePermissionsPersistence,
+            LegacyPermissionDataProvider permissionDataProvider, Object lock) {
         mLock = lock;
-        mPermissions = permission;
+        mPermissions = permissionSettings;
         mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
-                runtimePermissionsPersistence, mLock);
+                runtimePermissionsPersistence);
+        mPermissionDataProvider = permissionDataProvider;
 
         mSystemDir = new File(dataDir, "system");
         mSystemDir.mkdirs();
@@ -1239,7 +1247,7 @@
 
     void writeAllRuntimePermissionsLPr() {
         for (int userId : UserManagerService.getInstance().getUserIds()) {
-            mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
         }
     }
 
@@ -2102,7 +2110,7 @@
     }
 
     void readInstallPermissionsLPr(XmlPullParser parser,
-            PermissionsState permissionsState) throws IOException, XmlPullParserException {
+            AppIdPermissionState permissionsState) throws IOException, XmlPullParserException {
         int outerDepth = parser.getDepth();
         int type;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -2131,25 +2139,7 @@
                 final int flags = (flagsStr != null)
                         ? Integer.parseInt(flagsStr, 16) : 0;
 
-                if (granted) {
-                    if (permissionsState.grantInstallPermission(bp) ==
-                            PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                        Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
-                        XmlUtils.skipCurrentTag(parser);
-                    } else {
-                        permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
-                                PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                    }
-                } else {
-                    if (permissionsState.revokeInstallPermission(bp) ==
-                            PermissionsState.PERMISSION_OPERATION_FAILURE) {
-                        Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
-                        XmlUtils.skipCurrentTag(parser);
-                    } else {
-                        permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
-                                PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                    }
-                }
+                permissionsState.putInstallPermissionState(new PermissionState(bp, granted, flags));
             } else {
                 Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
                         + parser.getName());
@@ -2158,7 +2148,7 @@
         }
     }
 
-    void writePermissionsLPr(XmlSerializer serializer, List<PermissionState> permissionStates)
+    void writePermissionsLPr(XmlSerializer serializer, Collection<PermissionState> permissionStates)
             throws IOException {
         if (permissionStates.isEmpty()) {
             return;
@@ -2641,7 +2631,11 @@
                 }
 
                 final boolean isDebug = pkg.pkg.isDebuggable();
-                final int[] gids = pkg.getPermissionsState().computeGids(userIds);
+                final IntArray gids = new IntArray();
+                for (final int userId : userIds) {
+                    gids.addAll(mPermissionDataProvider.getGidsForUid(UserHandle.getUid(userId,
+                            pkg.appId)));
+                }
 
                 // Avoid any application that has a space in its path.
                 if (dataPath.indexOf(' ') >= 0)
@@ -2673,11 +2667,12 @@
                 sb.append(" ");
                 sb.append(AndroidPackageUtils.getSeInfo(pkg.pkg, pkg));
                 sb.append(" ");
-                if (gids != null && gids.length > 0) {
-                    sb.append(gids[0]);
-                    for (int i = 1; i < gids.length; i++) {
+                final int gidsSize = gids.size();
+                if (gids != null && gids.size() > 0) {
+                    sb.append(gids.get(0));
+                    for (int i = 1; i < gidsSize; i++) {
                         sb.append(",");
-                        sb.append(gids[i]);
+                        sb.append(gids.get(i));
                     }
                 } else {
                     sb.append("none");
@@ -4482,8 +4477,9 @@
     }
 
     void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
-            ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
-            Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
+            ArraySet<String> permissionNames, PackageSetting ps,
+            AppIdPermissionState permissionsState, SimpleDateFormat sdf, Date date,
+            List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
         AndroidPackage pkg = ps.pkg;
         if (checkinTag != null) {
             pw.print(checkinTag);
@@ -4810,7 +4806,6 @@
         }
 
         if (ps.sharedUser == null || permissionNames != null || dumpAll) {
-            PermissionsState permissionsState = ps.getPermissionsState();
             dumpInstallPermissionsLPr(pw, prefix + "  ", permissionNames, permissionsState);
         }
 
@@ -4889,8 +4884,8 @@
             }
 
             if (ps.sharedUser == null) {
-                PermissionsState permissionsState = ps.getPermissionsState();
-                dumpGidsLPr(pw, prefix + "    ", permissionsState.computeGids(user.id));
+                dumpGidsLPr(pw, prefix + "    ", mPermissionDataProvider.getGidsForUid(
+                        UserHandle.getUid(user.id, ps.appId)));
                 dumpRuntimePermissionsLPr(pw, prefix + "    ", permissionNames, permissionsState
                         .getRuntimePermissionStates(user.id), dumpAll);
             }
@@ -4933,8 +4928,10 @@
                     && !packageName.equals(ps.name)) {
                 continue;
             }
+            final AppIdPermissionState permissionsState =
+                    mPermissionDataProvider.getAppIdPermissionState(ps.appId);
             if (permissionNames != null
-                    && !ps.getPermissionsState().hasRequestedPermission(permissionNames)) {
+                    && !permissionsState.hasPermissionState(permissionNames)) {
                 continue;
             }
 
@@ -4948,8 +4945,8 @@
                 pw.println("Packages:");
                 printedSomething = true;
             }
-            dumpPackageLPr(pw, "  ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users,
-                    packageName != null, dumpAllComponents);
+            dumpPackageLPr(pw, "  ", checkin ? "pkg" : null, permissionNames, ps, permissionsState,
+                    sdf, date, users, packageName != null, dumpAllComponents);
         }
 
         printedSomething = false;
@@ -4989,8 +4986,10 @@
                     pw.println("Hidden system packages:");
                     printedSomething = true;
                 }
-                dumpPackageLPr(pw, "  ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
-                        users, packageName != null, dumpAllComponents);
+                final AppIdPermissionState permissionsState =
+                        mPermissionDataProvider.getAppIdPermissionState(ps.appId);
+                dumpPackageLPr(pw, "  ", checkin ? "dis" : null, permissionNames, ps,
+                        permissionsState, sdf, date, users, packageName != null, dumpAllComponents);
             }
         }
     }
@@ -5018,8 +5017,10 @@
             if (packageName != null && su != dumpState.getSharedUser()) {
                 continue;
             }
+            final AppIdPermissionState permissionsState =
+                    mPermissionDataProvider.getAppIdPermissionState(su.userId);
             if (permissionNames != null
-                    && !su.getPermissionsState().hasRequestedPermission(permissionNames)) {
+                    && !permissionsState.hasPermissionState(permissionNames)) {
                 continue;
             }
             if (!checkin) {
@@ -5054,12 +5055,12 @@
                     continue;
                 }
 
-                final PermissionsState permissionsState = su.getPermissionsState();
                 dumpInstallPermissionsLPr(pw, prefix, permissionNames, permissionsState);
 
                 for (int userId : UserManagerService.getInstance().getUserIds()) {
-                    final int[] gids = permissionsState.computeGids(userId);
-                    final List<PermissionState> permissions =
+                    final int[] gids = mPermissionDataProvider.getGidsForUid(UserHandle.getUid(
+                            userId, su.userId));
+                    final Collection<PermissionState> permissions =
                             permissionsState.getRuntimePermissionStates(userId);
                     if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
                         pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
@@ -5120,7 +5121,7 @@
     }
 
     void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
-            List<PermissionState> permissionStates, boolean dumpAll) {
+            Collection<PermissionState> permissionStates, boolean dumpAll) {
         if (!permissionStates.isEmpty() || dumpAll) {
             pw.print(prefix); pw.println("runtime permissions:");
             for (PermissionState permissionState : permissionStates) {
@@ -5161,8 +5162,9 @@
     }
 
     void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
-            PermissionsState permissionsState) {
-        List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates();
+            AppIdPermissionState permissionsState) {
+        Collection<PermissionState> permissionStates =
+                permissionsState.getInstallPermissionStates();
         if (!permissionStates.isEmpty()) {
             pw.print(prefix); pw.println("install permissions:");
             for (PermissionState permissionState : permissionStates) {
@@ -5202,9 +5204,9 @@
 
     public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
         if (sync) {
-            mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId);
         } else {
-            mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+            mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
         }
     }
 
@@ -5292,8 +5294,6 @@
 
         private final Handler mHandler = new MyHandler();
 
-        private final Object mPersistenceLock;
-
         @GuardedBy("mLock")
         private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
 
@@ -5313,10 +5313,8 @@
         // The mapping keys are user ids.
         private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
 
-        public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
-                Object persistenceLock) {
+        public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) {
             mPersistence = persistence;
-            mPersistenceLock = persistenceLock;
         }
 
         @GuardedBy("Settings.this.mLock")
@@ -5327,7 +5325,7 @@
         @GuardedBy("Settings.this.mLock")
         void setVersionLPr(int version, int userId) {
             mVersions.put(userId, version);
-            writePermissionsForUserAsyncLPr(userId);
+            writeStateForUserAsyncLPr(userId);
         }
 
         @GuardedBy("Settings.this.mLock")
@@ -5342,7 +5340,7 @@
                         + "set before trying to update the fingerprint.");
             }
             mFingerprints.put(userId, mExtendedFingerprint);
-            writePermissionsForUserAsyncLPr(userId);
+            writeStateForUserAsyncLPr(userId);
         }
 
         public void setPermissionControllerVersion(long version) {
@@ -5361,13 +5359,7 @@
             return Build.FINGERPRINT + "?pc_version=" + version;
         }
 
-        public void writePermissionsForUserSyncLPr(int userId) {
-            mHandler.removeMessages(userId);
-            writePermissionsSync(userId);
-        }
-
-        @GuardedBy("Settings.this.mLock")
-        public void writePermissionsForUserAsyncLPr(int userId) {
+        public void writeStateForUserAsyncLPr(int userId) {
             final long currentTimeMillis = SystemClock.uptimeMillis();
 
             if (mWriteScheduled.get(userId)) {
@@ -5399,59 +5391,53 @@
             }
         }
 
-        private void writePermissionsSync(int userId) {
-            RuntimePermissionsState runtimePermissions;
-            synchronized (mPersistenceLock) {
-                mWriteScheduled.delete(userId);
+        public void writeStateForUserSyncLPr(int userId) {
+            mHandler.removeMessages(userId);
+            mWriteScheduled.delete(userId);
 
-                int version = mVersions.get(userId, INITIAL_VERSION);
+            int version = mVersions.get(userId, INITIAL_VERSION);
 
-                String fingerprint = mFingerprints.get(userId);
+            String fingerprint = mFingerprints.get(userId);
 
-                Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
-                        new ArrayMap<>();
-                int packagesSize = mPackages.size();
-                for (int i = 0; i < packagesSize; i++) {
-                    String packageName = mPackages.keyAt(i);
-                    PackageSetting packageSetting = mPackages.valueAt(i);
-                    if (packageSetting.sharedUser == null) {
-                        List<RuntimePermissionsState.PermissionState> permissions =
-                                getPermissionsFromPermissionsState(
-                                        packageSetting.getPermissionsState(), userId);
-                        packagePermissions.put(packageName, permissions);
-                    }
-                }
-
-                Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
-                        new ArrayMap<>();
-                final int sharedUsersSize = mSharedUsers.size();
-                for (int i = 0; i < sharedUsersSize; i++) {
-                    String sharedUserName = mSharedUsers.keyAt(i);
-                    SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+            Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+                    new ArrayMap<>();
+            int packagesSize = mPackages.size();
+            for (int i = 0; i < packagesSize; i++) {
+                String packageName = mPackages.keyAt(i);
+                PackageSetting packageSetting = mPackages.valueAt(i);
+                if (packageSetting.sharedUser == null) {
                     List<RuntimePermissionsState.PermissionState> permissions =
                             getPermissionsFromPermissionsState(
-                                    sharedUserSetting.getPermissionsState(), userId);
-                    sharedUserPermissions.put(sharedUserName, permissions);
+                                    packageSetting.getPermissionsState(), userId);
+                    packagePermissions.put(packageName, permissions);
                 }
-
-                runtimePermissions = new RuntimePermissionsState(version, fingerprint,
-                        packagePermissions, sharedUserPermissions);
             }
 
+            Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+                    new ArrayMap<>();
+            final int sharedUsersSize = mSharedUsers.size();
+            for (int i = 0; i < sharedUsersSize; i++) {
+                String sharedUserName = mSharedUsers.keyAt(i);
+                SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+                List<RuntimePermissionsState.PermissionState> permissions =
+                        getPermissionsFromPermissionsState(
+                                sharedUserSetting.getPermissionsState(), userId);
+                sharedUserPermissions.put(sharedUserName, permissions);
+            }
+
+            RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
+                    fingerprint, packagePermissions, sharedUserPermissions);
+
             mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
         }
 
         @NonNull
         private List<RuntimePermissionsState.PermissionState> getPermissionsFromPermissionsState(
-                @NonNull PermissionsState permissionsState, @UserIdInt int userId) {
-            List<PermissionState> permissionStates = permissionsState.getRuntimePermissionStates(
-                    userId);
-            List<RuntimePermissionsState.PermissionState> permissions =
-                    new ArrayList<>();
-            int permissionStatesSize = permissionStates.size();
-            for (int i = 0; i < permissionStatesSize; i++) {
-                PermissionState permissionState = permissionStates.get(i);
-
+                @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) {
+            Collection<PermissionState> permissionStates =
+                    permissionsState.getRuntimePermissionStates(userId);
+            List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
+            for (PermissionState permissionState : permissionStates) {
                 RuntimePermissionsState.PermissionState permission =
                         new RuntimePermissionsState.PermissionState(permissionState.getName(),
                                 permissionState.isGranted(), permissionState.getFlags());
@@ -5480,7 +5466,7 @@
                     userId));
             if (runtimePermissions == null) {
                 readLegacyStateForUserSyncLPr(userId);
-                writePermissionsForUserAsyncLPr(userId);
+                writeStateForUserAsyncLPr(userId);
                 return;
             }
 
@@ -5536,7 +5522,7 @@
 
         private void readPermissionsStateLpr(
                 @NonNull List<RuntimePermissionsState.PermissionState> permissions,
-                @NonNull PermissionsState permissionsState, @UserIdInt int userId) {
+                @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) {
             int permissionsSize = permissions.size();
             for (int i = 0; i < permissionsSize; i++) {
                 RuntimePermissionsState.PermissionState permission = permissions.get(i);
@@ -5550,14 +5536,8 @@
                 boolean granted = permission.isGranted();
                 int flags = permission.getFlags();
 
-                if (granted) {
-                    permissionsState.grantRuntimePermission(basePermission, userId);
-                    permissionsState.updatePermissionFlags(basePermission, userId,
-                            PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                } else {
-                    permissionsState.updatePermissionFlags(basePermission, userId,
-                            PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                }
+                permissionsState.putRuntimePermissionState(new PermissionState(basePermission,
+                        granted, flags), userId);
             }
         }
 
@@ -5638,8 +5618,9 @@
             }
         }
 
-        private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState,
-                int userId) throws IOException, XmlPullParserException {
+        private void parsePermissionsLPr(XmlPullParser parser,
+                AppIdPermissionState permissionsState, int userId)
+                throws IOException, XmlPullParserException {
             final int outerDepth = parser.getDepth();
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -5666,15 +5647,8 @@
                         final int flags = (flagsStr != null)
                                 ? Integer.parseInt(flagsStr, 16) : 0;
 
-                        if (granted) {
-                            permissionsState.grantRuntimePermission(bp, userId);
-                            permissionsState.updatePermissionFlags(bp, userId,
-                                    PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                        } else {
-                            permissionsState.updatePermissionFlags(bp, userId,
-                                    PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
-                        }
-
+                        permissionsState.putRuntimePermissionState(new PermissionState(bp, granted,
+                                flags), userId);
                     }
                     break;
                 }
@@ -5690,7 +5664,9 @@
             public void handleMessage(Message message) {
                 final int userId = message.what;
                 Runnable callback = (Runnable) message.obj;
-                writePermissionsSync(userId);
+                synchronized (mLock) {
+                    writeStateForUserSyncLPr(userId);
+                }
                 if (callback != null) {
                     callback.run();
                 }
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index d413213..35c26d6 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -86,7 +86,6 @@
 import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 /**
@@ -226,7 +225,7 @@
         final IntArray childSessionIds = new IntArray();
         if (session.isMultiPackage()) {
             for (PackageInstallerSession s : session.getChildSessions()) {
-                if (isApexSession(s)) {
+                if (s.isApexSession()) {
                     childSessionIds.add(s.sessionId);
                 }
             }
@@ -329,31 +328,6 @@
         }
     }
 
-    private static boolean isApexSession(@NonNull PackageInstallerSession session) {
-        return (session.params.installFlags & PackageManager.INSTALL_APEX) != 0;
-    }
-
-    private boolean sessionContains(@NonNull PackageInstallerSession session,
-                                    Predicate<PackageInstallerSession> filter) {
-        if (!session.isMultiPackage()) {
-            return filter.test(session);
-        }
-        for (PackageInstallerSession s : session.getChildSessions()) {
-            if (filter.test(s)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean sessionContainsApex(@NonNull PackageInstallerSession session) {
-        return sessionContains(session, (s) -> isApexSession(s));
-    }
-
-    private boolean sessionContainsApk(@NonNull PackageInstallerSession session) {
-        return sessionContains(session, (s) -> !isApexSession(s));
-    }
-
     // Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
     private void abortCheckpoint(int sessionId, String errorMsg) {
         String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
@@ -400,7 +374,7 @@
         List<PackageInstallerSession> apexSessions = new ArrayList<>();
         if (session.isMultiPackage()) {
             for (PackageInstallerSession s : session.getChildSessions()) {
-                if (sessionContainsApex(s)) {
+                if (s.containsApexSession()) {
                     apexSessions.add(s);
                 }
             }
@@ -521,7 +495,7 @@
     private void resumeSession(@NonNull PackageInstallerSession session) {
         Slog.d(TAG, "Resuming session " + session.sessionId);
 
-        final boolean hasApex = sessionContainsApex(session);
+        final boolean hasApex = session.containsApexSession();
         ApexSessionInfo apexSessionInfo = null;
         if (hasApex) {
             // Check with apexservice whether the apex packages have been activated.
@@ -740,7 +714,7 @@
     @Nullable
     private PackageInstallerSession extractApksInSession(PackageInstallerSession session)
             throws PackageManagerException {
-        if (!session.isMultiPackage() && !isApexSession(session)) {
+        if (!session.isMultiPackage() && !session.isApexSession()) {
             return createAndWriteApkSession(session);
         } else if (session.isMultiPackage()) {
             // For multi-package staged sessions containing APKs, we identify which child sessions
@@ -749,7 +723,7 @@
             // sessions will be installed atomically.
             final List<PackageInstallerSession> childSessions = new ArrayList<>();
             for (PackageInstallerSession s : session.getChildSessions()) {
-                if (!isApexSession(s)) {
+                if (!s.isApexSession()) {
                     childSessions.add(s);
                 }
             }
@@ -798,7 +772,7 @@
         }
         final Set<String> apkNames = new ArraySet<>();
         for (PackageInstallerSession s : session.getChildSessions()) {
-            if (!isApexSession(s)) {
+            if (!s.isApexSession()) {
                 apkNames.add(s.getPackageName());
             }
         }
@@ -1020,7 +994,7 @@
      * @return returns true if it is ensured that there is no active apex session, otherwise false
      */
     private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
-        if (!sessionContainsApex(session)) {
+        if (!session.containsApexSession()) {
             return true;
         }
         final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
@@ -1342,7 +1316,7 @@
          */
         private void handlePreRebootVerification_Apex(
                 @NonNull PackageInstallerSession session, int rollbackId) {
-            final boolean hasApex = sessionContainsApex(session);
+            final boolean hasApex = session.containsApexSession();
 
             // APEX checks. For single-package sessions, check if they contain an APEX. For
             // multi-package sessions, find all the child sessions that contain an APEX.
@@ -1372,7 +1346,7 @@
          * {@link #notifyPreRebootVerification_Apk_Complete}
          */
         private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) {
-            if (!sessionContainsApk(session)) {
+            if (!session.containsApkSession()) {
                 notifyPreRebootVerification_Apk_Complete(session);
                 return;
             }
@@ -1421,7 +1395,7 @@
             Slog.d(TAG, "Marking session " + session.sessionId + " as ready");
             session.setStagedSessionReady();
             if (session.isStagedSessionReady()) {
-                final boolean hasApex = sessionContainsApex(session);
+                final boolean hasApex = session.containsApexSession();
                 if (hasApex) {
                     try {
                         mApexManager.markStagedSessionReady(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4c58b06..6b29129 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4709,7 +4709,7 @@
                 final boolean running = am.isUserRunning(user.id, 0);
                 final boolean current = user.id == currentUser;
                 if (verbose) {
-                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s\n", i, user.id, user.name,
+                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s\n", i, user.id, user.name,
                             UserInfo.flagsToString(user.flags),
                             running ? " (running)" : "",
                             user.partial ? " (partial)" : "",
diff --git a/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java
new file mode 100644
index 0000000..aabdafd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * Legacy permission state that was associated with packages or shared users.
+ */
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public final class AppIdPermissionState {
+    // Maps from user IDs to user states.
+    @NonNull
+    private final SparseArray<UserState> mUserStates = new SparseArray<>();
+
+    // Keyed by user IDs.
+    @NonNull
+    private final SparseBooleanArray mMissing = new SparseBooleanArray();
+
+    /**
+     * Copy from another permission state.
+     *
+     * @param other the other permission state.
+     *
+     * @hide
+     */
+    public void copyFrom(@NonNull AppIdPermissionState other) {
+        if (other == this) {
+            return;
+        }
+
+        mUserStates.clear();
+        final int userStatesSize = other.mUserStates.size();
+        for (int i = 0; i < userStatesSize; i++) {
+            mUserStates.put(other.mUserStates.keyAt(i),
+                    new UserState(other.mUserStates.valueAt(i)));
+        }
+
+        mMissing.clear();
+        final int missingSize = other.mMissing.size();
+        for (int i = 0; i < missingSize; i++) {
+            mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i));
+        }
+    }
+
+    /**
+     * Reset this permission state.
+     *
+     * @hide
+     */
+    public void reset() {
+        mUserStates.clear();
+        mMissing.clear();
+    }
+
+    @Override
+    public boolean equals(@Nullable Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object == null) {
+            return false;
+        }
+        if (getClass() != object.getClass()) {
+            return false;
+        }
+        final AppIdPermissionState other = (AppIdPermissionState) object;
+        return Objects.equals(mUserStates, other.mUserStates)
+                && Objects.equals(mMissing, other.mMissing);
+    }
+
+    /**
+     * Put a install permission state.
+     *
+     * @param permissionState the permission state
+     */
+    public void putInstallPermissionState(@NonNull PermissionState permissionState) {
+        putPermissionState(permissionState, UserHandle.USER_ALL);
+    }
+
+    /**
+     * Put a runtime permission state for a user.
+     *
+     * @param permissionState the permission state
+     * @param userId the user ID
+     */
+    public void putRuntimePermissionState(@NonNull PermissionState permissionState,
+            @UserIdInt int userId) {
+        checkUserId(userId);
+        putPermissionState(permissionState, userId);
+    }
+
+    private void putPermissionState(@NonNull PermissionState permissionState,
+            @UserIdInt int userId) {
+        UserState userState = mUserStates.get(userId);
+        if (userState == null) {
+            userState = new UserState();
+            mUserStates.put(userId, userState);
+        }
+        userState.putPermissionState(permissionState);
+    }
+
+    /**
+     * Check whether there are any permission states for the given permissions.
+     *
+     * @param permissionNames the permission names
+     * @return whether there are any permission states
+     *
+     * @hide
+     */
+    public boolean hasPermissionState(@NonNull Collection<String> permissionNames) {
+        final int userStatesSize = mUserStates.size();
+        for (int i = 0; i < userStatesSize; i++) {
+            final UserState userState = mUserStates.valueAt(i);
+            for (final String permissionName : permissionNames) {
+                if (userState.getPermissionState(permissionName) != null) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get all the install permission states.
+     *
+     * @return the install permission states
+     */
+    @NonNull
+    public Collection<PermissionState> getInstallPermissionStates() {
+        return getPermissionStates(UserHandle.USER_ALL);
+    }
+
+    /**
+     * Get all the runtime permission states for a user.
+     *
+     * @param userId the user ID
+     * @return the runtime permission states
+     */
+    @NonNull
+    public Collection<PermissionState> getRuntimePermissionStates(@UserIdInt int userId) {
+        checkUserId(userId);
+        return getPermissionStates(userId);
+    }
+
+    @NonNull
+    private Collection<PermissionState> getPermissionStates(@UserIdInt int userId) {
+        final UserState userState = mUserStates.get(userId);
+        if (userState == null) {
+            return Collections.emptyList();
+        }
+        return userState.getPermissionStates();
+    }
+
+    /**
+     * Check whether the permission state is missing for a user.
+     * <p>
+     * This can happen if permission state is rolled back and we'll need to generate a reasonable
+     * default state to keep the app usable.
+     *
+     * @param userId the user ID
+     * @return whether the permission state is missing
+     */
+    public boolean isMissing(@UserIdInt int userId) {
+        checkUserId(userId);
+        return mMissing.get(userId);
+    }
+
+    /**
+     * Set whether the permission state is missing for a user.
+     * <p>
+     * This can happen if permission state is rolled back and we'll need to generate a reasonable
+     * default state to keep the app usable.
+     *
+     * @param missing whether the permission state is missing
+     * @param userId the user ID
+     */
+    public void setMissing(boolean missing, @UserIdInt int userId) {
+        checkUserId(userId);
+        if (missing) {
+            mMissing.put(userId, true);
+        } else {
+            mMissing.delete(userId);
+        }
+    }
+
+    private static void checkUserId(@UserIdInt int userId) {
+        if (userId < 0) {
+            throw new IllegalArgumentException("Invalid user ID " + userId);
+        }
+    }
+
+    /**
+     * Legacy state for permissions for a user.
+     */
+    private static final class UserState {
+        // Maps from permission names to permission states.
+        @NonNull
+        private final ArrayMap<String, PermissionState> mPermissionStates = new ArrayMap<>();
+
+        public UserState() {}
+
+        public UserState(@NonNull UserState other) {
+            final int permissionStatesSize = other.mPermissionStates.size();
+            for (int i = 0; i < permissionStatesSize; i++) {
+                mPermissionStates.put(other.mPermissionStates.keyAt(i),
+                        new PermissionState(other.mPermissionStates.valueAt(i)));
+            }
+        }
+
+        @Nullable
+        public PermissionState getPermissionState(@NonNull String permissionName) {
+            return mPermissionStates.get(permissionName);
+        }
+
+        public void putPermissionState(@NonNull PermissionState permissionState) {
+            mPermissionStates.put(permissionState.getName(), permissionState);
+        }
+
+        @NonNull
+        public Collection<PermissionState> getPermissionStates() {
+            return Collections.unmodifiableCollection(mPermissionStates.values());
+        }
+    }
+
+    /**
+     * Legacy state for a single permission.
+     */
+    public static final class PermissionState {
+        @NonNull
+        private final BasePermission mPermission;
+
+        private final boolean mGranted;
+
+        private final int mFlags;
+
+        /**
+         * Create a new instance of this class.
+         *
+         * @param permission the {@link BasePermission} for the permission
+         * @param granted whether the permission is granted
+         * @param flags the permission flags
+         */
+        public PermissionState(@NonNull BasePermission permission, boolean granted, int flags) {
+            mPermission = permission;
+            mGranted = granted;
+            mFlags = flags;
+        }
+
+        private PermissionState(@NonNull PermissionState other) {
+            mPermission = other.mPermission;
+            mGranted = other.mGranted;
+            mFlags = other.mFlags;
+        }
+
+        /**
+         * Get the {@link BasePermission} for the permission.
+         *
+         * @return the {@link BasePermission}
+         */
+        @NonNull
+        public BasePermission getPermission() {
+            return mPermission;
+        }
+
+        /**
+         * Get the permission name.
+         *
+         * @return the permission name
+         */
+        @NonNull
+        public String getName() {
+            return mPermission.getName();
+        }
+
+        /**
+         * Get whether the permission is granted.
+         *
+         * @return whether the permission is granted
+         */
+        @NonNull
+        public boolean isGranted() {
+            return mGranted;
+        }
+
+        /**
+         * Get the permission flags.
+         *
+         * @return the permission flags
+         */
+        @NonNull
+        public int getFlags() {
+            return mFlags;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
new file mode 100644
index 0000000..7452b52
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
@@ -0,0 +1,44 @@
+/*
+ * 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.permission;
+
+import android.annotation.AppIdInt;
+import android.annotation.NonNull;
+
+/**
+ * An interface for legacy code to read permission data in order to maintain compatibility.
+ */
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface LegacyPermissionDataProvider {
+    /**
+     * Get the legacy permission state of an app ID, either a package or a shared user.
+     *
+     * @param appId the app ID
+     * @return the legacy permission state
+     */
+    @NonNull
+    public abstract AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId);
+
+    /**
+     * Get the GIDs computed from the permission state of a UID, either a package or a shared user.
+     *
+     * @param uid the UID
+     * @return the GIDs for the UID
+     */
+    @NonNull
+    public abstract int[] getGidsForUid(int uid);
+}
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 2f9e199..840b233 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -58,6 +58,7 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.Manifest;
+import android.annotation.AppIdInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -182,8 +183,6 @@
     private static final int GRANT_INSTALL = 2;
     /** Permission grant: grant the permission as a runtime one. */
     private static final int GRANT_RUNTIME = 3;
-    /** Permission grant: grant as runtime a permission that was granted as an install time one. */
-    private static final int GRANT_UPGRADE = 4;
 
     private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
 
@@ -2514,20 +2513,6 @@
         return permission.computeGids(userId);
     }
 
-    @Nullable
-    private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
-        final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
-        if (ps == null) {
-            return null;
-        }
-        final UidPermissionState uidState = getUidState(ps, userId);
-        if (uidState == null) {
-            Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
-            return null;
-        }
-        return uidState.computeGids(userId);
-    }
-
     /**
      * Restore the permission state for a package.
      *
@@ -2700,7 +2685,7 @@
                             SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
                             String splitPermName = sp.getSplitPermission();
                             if (sp.getNewPermissions().contains(permName)
-                                    && origState.hasInstallPermission(splitPermName)) {
+                                    && origState.hasPermission(splitPermName)) {
                                 upgradedActivityRecognitionPermission = splitPermName;
                                 newImplicitPermissions.add(permName);
 
@@ -2746,15 +2731,8 @@
                     // For all apps normal permissions are install time ones.
                     grant = GRANT_INSTALL;
                 } else if (bp.isRuntime()) {
-                    if (origState.hasInstallPermission(bp.getName())
-                            || upgradedActivityRecognitionPermission != null) {
-                        // Before Q we represented some runtime permissions as install permissions,
-                        // in Q we cannot do this anymore. Hence upgrade them all.
-                        grant = GRANT_UPGRADE;
-                    } else {
-                        // For modern apps keep runtime permissions unchanged.
-                        grant = GRANT_RUNTIME;
-                    }
+                    // For modern apps keep runtime permissions unchanged.
+                    grant = GRANT_RUNTIME;
                 } else if (bp.isSignature()) {
                     // For all apps signature permissions are install time ones.
                     allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origState);
@@ -2763,19 +2741,16 @@
                     }
                 }
 
-                if (grant != GRANT_DENIED) {
-                    if (!ps.isSystem() && userState.areInstallPermissionsFixed(ps.name)
-                            && !bp.isRuntime()) {
-                        // If this is an existing, non-system package, then
-                        // we can't add any new permissions to it. Runtime
-                        // permissions can be added any time - they ad dynamic.
-                        if (!allowedSig && !origState.hasInstallPermission(perm)) {
-                            // Except...  if this is a permission that was added
-                            // to the platform (note: need to only do this when
-                            // updating the platform).
-                            if (!isNewPlatformPermissionForPackage(perm, pkg)) {
-                                grant = GRANT_DENIED;
-                            }
+                if (grant == GRANT_INSTALL && !allowedSig && !origState.hasPermission(perm)) {
+                    // If this is an existing, non-system package, then
+                    // we can't add any new permissions to it. Runtime
+                    // permissions can be added any time - they are dynamic.
+                    if (!ps.isSystem() && userState.areInstallPermissionsFixed(ps.name)) {
+                        // Except...  if this is a permission that was added
+                        // to the platform (note: need to only do this when
+                        // updating the platform).
+                        if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+                            grant = GRANT_DENIED;
                         }
                     }
                 }
@@ -2789,22 +2764,6 @@
                     if (grant != GRANT_DENIED) {
                         switch (grant) {
                             case GRANT_INSTALL: {
-                                // Revoke this as runtime permission to handle the case of
-                                // a runtime permission being downgraded to an install one.
-                                // Also in permission review mode we keep dangerous permissions
-                                // for legacy apps
-                                final PermissionState origPermissionState =
-                                        origState.getPermissionState(perm);
-                                if (origPermissionState != null
-                                        && origPermissionState.isRuntime()) {
-                                    // Revoke the runtime permission and clear the flags.
-                                    origState.revokePermission(bp);
-                                    origState.updatePermissionFlags(bp,
-                                            PackageManager.MASK_PERMISSION_FLAGS_ALL, 0);
-                                    // If we revoked a permission permission, we have to write.
-                                    updatedUserIds = ArrayUtils.appendInt(
-                                            updatedUserIds, userId);
-                                }
                                 // Grant an install permission.
                                 if (uidState.grantPermission(bp) != PERMISSION_OPERATION_FAILURE) {
                                     changedInstallPermission = true;
@@ -2869,7 +2828,8 @@
                                     // Hard restricted permissions cannot be held.
                                     } else if (!permissionPolicyInitialized
                                             || (!hardRestricted || restrictionExempt)) {
-                                        if (origPermState != null && origPermState.isGranted()) {
+                                        if ((origPermState != null && origPermState.isGranted())
+                                                || upgradedActivityRecognitionPermission != null) {
                                             if (uidState.grantPermission(bp)
                                                     == PERMISSION_OPERATION_FAILURE) {
                                                 wasChanged = true;
@@ -2927,124 +2887,6 @@
                                         flags);
                             } break;
 
-                            case GRANT_UPGRADE: {
-                                // Upgrade from Pre-Q to Q permission model. Make all permissions
-                                // runtime
-                                PermissionState origPermState = origState.getPermissionState(perm);
-                                int flags = (origPermState != null) ? origPermState.getFlags() : 0;
-
-                                BasePermission bpToRevoke =
-                                        upgradedActivityRecognitionPermission == null
-                                        ? bp : mSettings.getPermissionLocked(
-                                                upgradedActivityRecognitionPermission);
-                                // Remove install permission
-                                if (origState.revokePermission(bpToRevoke)
-                                        != PERMISSION_OPERATION_FAILURE) {
-                                    origState.updatePermissionFlags(bpToRevoke,
-                                            (MASK_PERMISSION_FLAGS_ALL
-                                                    & ~FLAG_PERMISSION_APPLY_RESTRICTION), 0);
-                                    changedInstallPermission = true;
-                                }
-
-                                boolean hardRestricted = bp.isHardRestricted();
-                                boolean softRestricted = bp.isSoftRestricted();
-
-                                // If permission policy is not ready we don't deal with restricted
-                                // permissions as the policy may whitelist some permissions. Once
-                                // the policy is initialized we would re-evaluate permissions.
-                                final boolean permissionPolicyInitialized =
-                                        mPermissionPolicyInternal != null
-                                                && mPermissionPolicyInternal.isInitialized(userId);
-
-                                boolean wasChanged = false;
-
-                                boolean restrictionExempt =
-                                        (origState.getPermissionFlags(bp.name)
-                                                & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
-                                boolean restrictionApplied = (origState.getPermissionFlags(
-                                        bp.name) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-
-                                if (appSupportsRuntimePermissions) {
-                                    // If hard restricted we don't allow holding it
-                                    if (permissionPolicyInitialized && hardRestricted) {
-                                        if (!restrictionExempt) {
-                                            if (origPermState != null && origPermState.isGranted()
-                                                    && uidState.revokePermission(
-                                                    bp) != PERMISSION_OPERATION_FAILURE) {
-                                                wasChanged = true;
-                                            }
-                                            if (!restrictionApplied) {
-                                                flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
-                                                wasChanged = true;
-                                            }
-                                        }
-                                    // If soft restricted we allow holding in a restricted form
-                                    } else if (permissionPolicyInitialized && softRestricted) {
-                                        // Regardless if granted set the  restriction flag as it
-                                        // may affect app treatment based on this permission.
-                                        if (!restrictionExempt && !restrictionApplied) {
-                                            flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
-                                            wasChanged = true;
-                                        }
-                                    }
-
-                                    // Remove review flag as it is not necessary anymore
-                                    if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                                        flags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;
-                                        wasChanged = true;
-                                    }
-
-                                    if ((flags & FLAG_PERMISSION_REVOKED_COMPAT) != 0) {
-                                        flags &= ~FLAG_PERMISSION_REVOKED_COMPAT;
-                                        wasChanged = true;
-                                    // Hard restricted permissions cannot be held.
-                                    } else if (!permissionPolicyInitialized ||
-                                            (!hardRestricted || restrictionExempt)) {
-                                        if (uidState.grantPermission(bp)
-                                                != PERMISSION_OPERATION_FAILURE) {
-                                             wasChanged = true;
-                                        }
-                                    }
-                                } else {
-                                    if (!uidState.hasPermission(bp.name)
-                                            && uidState.grantPermission(bp)
-                                                    != PERMISSION_OPERATION_FAILURE) {
-                                        flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
-                                        wasChanged = true;
-                                    }
-
-                                    // If legacy app always grant the permission but if restricted
-                                    // and not exempt take a note a restriction should be applied.
-                                    if (permissionPolicyInitialized
-                                            && (hardRestricted || softRestricted)
-                                                    && !restrictionExempt && !restrictionApplied) {
-                                        flags |= FLAG_PERMISSION_APPLY_RESTRICTION;
-                                        wasChanged = true;
-                                    }
-                                }
-
-                                // If unrestricted or restriction exempt, don't apply restriction.
-                                if (permissionPolicyInitialized) {
-                                    if (!(hardRestricted || softRestricted) || restrictionExempt) {
-                                        if (restrictionApplied) {
-                                            flags &= ~FLAG_PERMISSION_APPLY_RESTRICTION;
-                                            // Dropping restriction on a legacy app implies a review
-                                            if (!appSupportsRuntimePermissions) {
-                                                flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
-                                            }
-                                            wasChanged = true;
-                                        }
-                                    }
-                                }
-
-                                if (wasChanged) {
-                                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
-                                }
-
-                                uidState.updatePermissionFlags(bp,
-                                        MASK_PERMISSION_FLAGS_ALL, flags);
-                            } break;
-
                             default: {
                                 if (packageOfInterest == null
                                         || packageOfInterest.equals(pkg.getPackageName())) {
@@ -3153,11 +2995,11 @@
 
         for (String permission : ps.getPermissions()) {
             if (!pkg.getImplicitPermissions().contains(permission)) {
-                if (!ps.hasInstallPermission(permission)) {
+                BasePermission bp = mSettings.getPermissionLocked(permission);
+                if (bp.isRuntime()) {
                     int flags = ps.getPermissionFlags(permission);
 
                     if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
-                        BasePermission bp = mSettings.getPermissionLocked(permission);
 
                         int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
 
@@ -3303,8 +3145,8 @@
             ArraySet<String> sourcePerms = newToSplitPerms.get(newPerm);
 
             if (sourcePerms != null) {
-                if (!ps.hasInstallPermission(newPerm)) {
-                    BasePermission bp = mSettings.getPermissionLocked(newPerm);
+                BasePermission bp = mSettings.getPermissionLocked(newPerm);
+                if (bp.isRuntime()) {
 
                     if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
                         ps.updatePermissionFlags(bp,
@@ -3313,27 +3155,31 @@
                     }
                     updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
 
-                    boolean inheritsFromInstallPerm = false;
-                    for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
-                            sourcePermNum++) {
-                        if (ps.hasInstallPermission(sourcePerms.valueAt(sourcePermNum))) {
-                            inheritsFromInstallPerm = true;
-                            break;
+                    if (!origPs.hasRequestedPermission(sourcePerms)) {
+                        boolean inheritsFromInstallPerm = false;
+                        for (int sourcePermNum = 0; sourcePermNum < sourcePerms.size();
+                                sourcePermNum++) {
+                            final String sourcePerm = sourcePerms.valueAt(sourcePermNum);
+                            BasePermission sourceBp = mSettings.getPermissionLocked(sourcePerm);
+                            if (!sourceBp.isRuntime()) {
+                                inheritsFromInstallPerm = true;
+                                break;
+                            }
+                        }
+
+                        if (!inheritsFromInstallPerm) {
+                            // Both permissions are new so nothing to inherit.
+                            if (DEBUG_PERMISSIONS) {
+                                Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
+                                        + " for " + pkgName + " as split permission is also new");
+                            }
+                            continue;
                         }
                     }
 
-                    if (!origPs.hasRequestedPermission(sourcePerms)
-                            && !inheritsFromInstallPerm) {
-                        // Both permissions are new so nothing to inherit.
-                        if (DEBUG_PERMISSIONS) {
-                            Slog.i(TAG, newPerm + " does not inherit from " + sourcePerms
-                                    + " for " + pkgName + " as split permission is also new");
-                        }
-                    } else {
-                        // Inherit from new install or existing runtime permissions
-                        inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms,
-                                newPerm, ps, pkg);
-                    }
+                    // Inherit from new install or existing runtime permissions
+                    inheritPermissionStateToNewImplicitPermissionLocked(sourcePerms, newPerm, ps,
+                            pkg);
                 }
             }
         }
@@ -3619,7 +3465,7 @@
             if (!allowed && bp.isDevelopment()) {
                 // For development permissions, a development permission
                 // is granted only if it was already granted.
-                allowed = origPermissions.hasInstallPermission(perm);
+                allowed = origPermissions.hasPermission(perm);
             }
             if (!allowed && bp.isSetup()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
@@ -4766,7 +4612,7 @@
         }
     }
 
-    private void removeAppState(int appId) {
+    private void removeAppIdState(@AppIdInt int appId) {
         synchronized (mLock) {
             final int[] userIds = mState.getUserIds();
             for (final int userId : userIds) {
@@ -4780,7 +4626,7 @@
         final int[] userIds = getAllUserIds();
         mPackageManagerInt.forEachPackageSetting(ps -> {
             final int appId = ps.getAppId();
-            final PermissionsState permissionsState = ps.getPermissionsState();
+            final AppIdPermissionState appIdState = ps.getPermissionsState();
 
             synchronized (mLock) {
                 for (final int userId : userIds) {
@@ -4789,25 +4635,21 @@
                     userState.setInstallPermissionsFixed(ps.name, ps.areInstallPermissionsFixed());
                     final UidPermissionState uidState = userState.getOrCreateUidState(appId);
                     uidState.reset();
-                    uidState.setGlobalGids(permissionsState.getGlobalGids());
-                    uidState.setMissing(permissionsState.isMissing(userId));
+                    uidState.setMissing(appIdState.isMissing(userId));
                     readStateFromPermissionStates(uidState,
-                            permissionsState.getInstallPermissionStates(), false);
+                            appIdState.getInstallPermissionStates());
                     readStateFromPermissionStates(uidState,
-                            permissionsState.getRuntimePermissionStates(userId), true);
+                            appIdState.getRuntimePermissionStates(userId));
                 }
             }
         });
     }
 
     private void readStateFromPermissionStates(@NonNull UidPermissionState uidState,
-            @NonNull List<PermissionsState.PermissionState> permissionStates, boolean isRuntime) {
-        final int permissionStatesSize = permissionStates.size();
-        for (int i = 0; i < permissionStatesSize; i++) {
-            final PermissionsState.PermissionState permissionState = permissionStates.get(i);
-            final BasePermission permission = permissionState.getPermission();
-            uidState.putPermissionState(permission, isRuntime, permissionState.isGranted(),
-                    permissionState.getFlags());
+            @NonNull Collection<AppIdPermissionState.PermissionState> permissionStates) {
+        for (final AppIdPermissionState.PermissionState permissionState : permissionStates) {
+            uidState.putPermissionState(permissionState.getPermission(),
+                    permissionState.isGranted(), permissionState.getFlags());
         }
     }
 
@@ -4815,8 +4657,8 @@
         final int[] userIds = mState.getUserIds();
         mPackageManagerInt.forEachPackageSetting(ps -> {
             ps.setInstallPermissionsFixed(false);
-            final PermissionsState permissionsState = ps.getPermissionsState();
-            permissionsState.reset();
+            final AppIdPermissionState appIdState = ps.getPermissionsState();
+            appIdState.reset();
             final int appId = ps.getAppId();
 
             synchronized (mLock) {
@@ -4838,27 +4680,21 @@
                         continue;
                     }
 
-                    permissionsState.setGlobalGids(uidState.getGlobalGids());
-                    permissionsState.setMissing(uidState.isMissing(), userId);
+                    appIdState.setMissing(uidState.isMissing(), userId);
                     final List<PermissionState> permissionStates = uidState.getPermissionStates();
                     final int permissionStatesSize = permissionStates.size();
                     for (int i = 0; i < permissionStatesSize; i++) {
                         final PermissionState permissionState = permissionStates.get(i);
 
-                        final BasePermission permission = permissionState.getPermission();
-                        if (permissionState.isGranted()) {
-                            if (permissionState.isRuntime()) {
-                                permissionsState.grantRuntimePermission(permission, userId);
-                            } else {
-                                permissionsState.grantInstallPermission(permission);
-                            }
-                        }
-                        final int flags = permissionState.getFlags();
-                        if (flags != 0) {
-                            final int flagsUserId = permissionState.isRuntime() ? userId
-                                    : UserHandle.USER_ALL;
-                            permissionsState.updatePermissionFlags(permission, flagsUserId, flags,
-                                    flags);
+                        final AppIdPermissionState.PermissionState legacyPermissionState =
+                                new AppIdPermissionState.PermissionState(
+                                        permissionState.getPermission(),
+                                        permissionState.isGranted(), permissionState.getFlags());
+                        if (permissionState.isRuntime()) {
+                            appIdState.putRuntimePermissionState(legacyPermissionState,
+                                    userId);
+                        } else {
+                            appIdState.putInstallPermissionState(legacyPermissionState);
                         }
                     }
                 }
@@ -4866,6 +4702,48 @@
         });
     }
 
+    @NonNull
+    private AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) {
+        final AppIdPermissionState appIdState = new AppIdPermissionState();
+        final int[] userIds = mState.getUserIds();
+        for (final int userId : userIds) {
+            final UidPermissionState uidState = getUidState(appId, userId);
+            if (uidState == null) {
+                Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID "
+                        + userId);
+                continue;
+            }
+
+            final List<PermissionState> permissionStates = uidState.getPermissionStates();
+            final int permissionStatesSize = permissionStates.size();
+            for (int i = 0; i < permissionStatesSize; i++) {
+                final PermissionState permissionState = permissionStates.get(i);
+
+                final AppIdPermissionState.PermissionState legacyPermissionState =
+                        new AppIdPermissionState.PermissionState(permissionState.getPermission(),
+                                permissionState.isGranted(), permissionState.getFlags());
+                if (permissionState.isRuntime()) {
+                    appIdState.putRuntimePermissionState(legacyPermissionState, userId);
+                } else if (userId == UserHandle.USER_SYSTEM) {
+                    appIdState.putInstallPermissionState(legacyPermissionState);
+                }
+            }
+        }
+        return appIdState;
+    }
+
+    @NonNull
+    private int[] getGidsForUid(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        final int userId = UserHandle.getUserId(uid);
+        final UidPermissionState uidState = getUidState(appId, userId);
+        if (uidState == null) {
+            Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId);
+            return EMPTY_INT_ARRAY;
+        }
+        return uidState.computeGids(userId);
+    }
+
     private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
         @Override
         public void systemReady() {
@@ -4910,8 +4788,8 @@
             PermissionManagerService.this.onUserRemoved(userId);
         }
         @Override
-        public void removePermissionsStateTEMP(int appId) {
-            PermissionManagerService.this.removeAppState(appId);
+        public void removeAppIdStateTEMP(@AppIdInt int appId) {
+            PermissionManagerService.this.removeAppIdState(appId);
         }
         @Override
         @UserIdInt
@@ -4931,11 +4809,6 @@
         public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
             return PermissionManagerService.this.getPermissionGids(permissionName, userId);
         }
-        @Nullable
-        @Override
-        public int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
-            return PermissionManagerService.this.getPackageGids(packageName, userId);
-        }
         @Override
         public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
                 String[] grantedPermissions, int callingUid) {
@@ -5263,6 +5136,16 @@
                 }
             }
         }
+
+        @NonNull
+        public AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) {
+            return PermissionManagerService.this.getAppIdPermissionState(appId);
+        }
+
+        @NonNull
+        public int[] getGidsForUid(int uid) {
+            return PermissionManagerService.this.getGidsForUid(uid);
+        }
     }
 
     private static final class OnPermissionChangeListeners extends Handler {
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 6d9bd2a..5ea3458 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -37,8 +37,8 @@
  *
  * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
  */
-public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
-
+public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal
+        implements LegacyPermissionDataProvider {
     /**
      * Provider for package names.
      */
@@ -288,13 +288,13 @@
     public abstract void onUserRemoved(@UserIdInt int userId);
 
     /**
-     * Remove the {@code PermissionsState} associated with an app ID, called the same time as the
+     * Remove the permission state associated with an app ID, called the same time as the
      * removal of a {@code PackageSetitng}.
      *
      * TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app
      * ID removal via API.
      */
-    public abstract void removePermissionsStateTEMP(int appId);
+    public abstract void removeAppIdStateTEMP(@AppIdInt int appId);
 
     /**
      * Update the shared user setting when a package with a shared user id is removed. The gids
@@ -324,12 +324,6 @@
     @Nullable
     public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId);
 
-    /**
-     * Get the GIDs computed from the permission state of a package.
-     */
-    @Nullable
-    public abstract int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId);
-
     /** Retrieve the packages that have requested the given app op permission */
     public abstract @Nullable String[] getAppOpPermissionPackages(
             @NonNull String permName, int callingUid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionState.java b/services/core/java/com/android/server/pm/permission/PermissionState.java
index 2ed9a50..38264c8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionState.java
@@ -41,13 +41,12 @@
     @GuardedBy("mLock")
     private int mFlags;
 
-    public PermissionState(@NonNull BasePermission permission, boolean isRuntime) {
+    public PermissionState(@NonNull BasePermission permission) {
         mPermission = permission;
-        mRuntime = isRuntime;
     }
 
     public PermissionState(@NonNull PermissionState other) {
-        this(other.mPermission, other.mRuntime);
+        this(other.mPermission);
 
         mGranted = other.mGranted;
         mFlags = other.mFlags;
@@ -70,7 +69,7 @@
 
     public boolean isRuntime() {
         synchronized (mLock) {
-            return mRuntime;
+            return mPermission.isRuntime();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
deleted file mode 100644
index 4fb2d5f..0000000
--- a/services/core/java/com/android/server/pm/permission/PermissionsState.java
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.permission;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * This class encapsulates the permissions for a package or a shared user.
- * <p>
- * There are two types of permissions: install (granted at installation)
- * and runtime (granted at runtime). Install permissions are granted to
- * all device users while runtime permissions are granted explicitly to
- * specific users.
- * </p>
- * <p>
- * The permissions are kept on a per device user basis. For example, an
- * application may have some runtime permissions granted under the device
- * owner but not granted under the secondary user.
- * <p>
- * This class is also responsible for keeping track of the Linux gids per
- * user for a package or a shared user. The gids are computed as a set of
- * the gids for all granted permissions' gids on a per user basis.
- * </p>
- */
-public final class PermissionsState {
-
-    /** The permission operation failed. */
-    public static final int PERMISSION_OPERATION_FAILURE = -1;
-
-    /** The permission operation succeeded and no gids changed. */
-    public static final int PERMISSION_OPERATION_SUCCESS = 0;
-
-    /** The permission operation succeeded and gids changed. */
-    public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
-
-    private static final int[] NO_GIDS = {};
-
-    private final Object mLock = new Object();
-
-    @GuardedBy("mLock")
-    private ArrayMap<String, PermissionData> mPermissions;
-
-    private int[] mGlobalGids = NO_GIDS;
-
-    @Nullable
-    private SparseBooleanArray mMissing;
-
-    private SparseBooleanArray mPermissionReviewRequired;
-
-    public PermissionsState() {
-        /* do nothing */
-    }
-
-    public PermissionsState(PermissionsState prototype) {
-        copyFrom(prototype);
-    }
-
-    public int[] getGlobalGids() {
-        return mGlobalGids;
-    }
-
-    /**
-     * Sets the global gids, applicable to all users.
-     *
-     * @param globalGids The global gids.
-     */
-    public void setGlobalGids(int[] globalGids) {
-        if (!ArrayUtils.isEmpty(globalGids)) {
-            mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
-        }
-    }
-
-    private static void invalidateCache() {
-        PackageManager.invalidatePackageInfoCache();
-    }
-
-    /**
-     * Initialized this instance from another one.
-     *
-     * @param other The other instance.
-     */
-    public void copyFrom(PermissionsState other) {
-        if (other == this) {
-            return;
-        }
-
-        synchronized (mLock) {
-            if (mPermissions != null) {
-                if (other.mPermissions == null) {
-                    mPermissions = null;
-                } else {
-                    mPermissions.clear();
-                }
-            }
-            if (other.mPermissions != null) {
-                if (mPermissions == null) {
-                    mPermissions = new ArrayMap<>();
-                }
-                final int permissionCount = other.mPermissions.size();
-                for (int i = 0; i < permissionCount; i++) {
-                    String name = other.mPermissions.keyAt(i);
-                    PermissionData permissionData = other.mPermissions.valueAt(i);
-                    mPermissions.put(name, new PermissionData(permissionData));
-                }
-            }
-        }
-
-        mGlobalGids = NO_GIDS;
-        if (other.mGlobalGids != NO_GIDS) {
-            mGlobalGids = Arrays.copyOf(other.mGlobalGids,
-                    other.mGlobalGids.length);
-        }
-
-        if (mMissing != null) {
-            if (other.mMissing == null) {
-                mMissing = null;
-            } else {
-                mMissing.clear();
-            }
-        }
-        if (other.mMissing != null) {
-            if (mMissing == null) {
-                mMissing = new SparseBooleanArray();
-            }
-            final int missingSize = other.mMissing.size();
-            for (int i = 0; i < missingSize; i++) {
-                mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i));
-            }
-        }
-
-        if (mPermissionReviewRequired != null) {
-            if (other.mPermissionReviewRequired == null) {
-                mPermissionReviewRequired = null;
-            } else {
-                mPermissionReviewRequired.clear();
-            }
-        }
-        if (other.mPermissionReviewRequired != null) {
-            if (mPermissionReviewRequired == null) {
-                mPermissionReviewRequired = new SparseBooleanArray();
-            }
-            final int userCount = other.mPermissionReviewRequired.size();
-            for (int i = 0; i < userCount; i++) {
-                final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
-                mPermissionReviewRequired.put(other.mPermissionReviewRequired.keyAt(i),
-                        reviewRequired);
-            }
-        }
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final PermissionsState other = (PermissionsState) obj;
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                if (other.mPermissions != null) {
-                    return false;
-                }
-            } else if (!mPermissions.equals(other.mPermissions)) {
-                return false;
-            }
-        }
-
-        if (!Objects.equals(mMissing, other.mMissing)) {
-            return false;
-        }
-
-        if (mPermissionReviewRequired == null) {
-            if (other.mPermissionReviewRequired != null) {
-                return false;
-            }
-        } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
-            return false;
-        }
-        return Arrays.equals(mGlobalGids, other.mGlobalGids);
-    }
-
-    /**
-     * Check whether the permissions state is missing for a user. This can happen if permission
-     * state is rolled back and we'll need to generate a reasonable default state to keep the app
-     * usable.
-     */
-    public boolean isMissing(@UserIdInt int userId) {
-        return mMissing != null && mMissing.get(userId);
-    }
-
-    /**
-     * Set whether the permissions state is missing for a user. This can happen if permission state
-     * is rolled back and we'll need to generate a reasonable default state to keep the app usable.
-     */
-    public void setMissing(boolean missing, @UserIdInt int userId) {
-        if (missing) {
-            if (mMissing == null) {
-                mMissing = new SparseBooleanArray();
-            }
-            mMissing.put(userId, true);
-        } else {
-            if (mMissing != null) {
-                mMissing.delete(userId);
-                if (mMissing.size() == 0) {
-                    mMissing = null;
-                }
-            }
-        }
-    }
-
-    public boolean isPermissionReviewRequired(int userId) {
-        return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
-    }
-
-    /**
-     * Grant an install permission.
-     *
-     * @param permission The permission to grant.
-     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
-     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
-     *     #PERMISSION_OPERATION_FAILURE}.
-     */
-    public int grantInstallPermission(BasePermission permission) {
-        return grantPermission(permission, UserHandle.USER_ALL);
-    }
-
-    /**
-     * Revoke an install permission.
-     *
-     * @param permission The permission to revoke.
-     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
-     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
-     *     #PERMISSION_OPERATION_FAILURE}.
-     */
-    public int revokeInstallPermission(BasePermission permission) {
-        return revokePermission(permission, UserHandle.USER_ALL);
-    }
-
-    /**
-     * Grant a runtime permission for a given device user.
-     *
-     * @param permission The permission to grant.
-     * @param userId The device user id.
-     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
-     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
-     *     #PERMISSION_OPERATION_FAILURE}.
-     */
-    public int grantRuntimePermission(BasePermission permission, int userId) {
-        enforceValidUserId(userId);
-        if (userId == UserHandle.USER_ALL) {
-            return PERMISSION_OPERATION_FAILURE;
-        }
-        return grantPermission(permission, userId);
-    }
-
-    /**
-     *  Revoke a runtime permission for a given device user.
-     *
-     * @param permission The permission to revoke.
-     * @param userId The device user id.
-     * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
-     *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
-     *     #PERMISSION_OPERATION_FAILURE}.
-     */
-    public int revokeRuntimePermission(BasePermission permission, int userId) {
-        enforceValidUserId(userId);
-        if (userId == UserHandle.USER_ALL) {
-            return PERMISSION_OPERATION_FAILURE;
-        }
-        return revokePermission(permission, userId);
-    }
-
-    /**
-     * Gets whether this state has a given runtime permission for a
-     * given device user id.
-     *
-     * @param name The permission name.
-     * @param userId The device user id.
-     * @return Whether this state has the permission.
-     */
-    public boolean hasRuntimePermission(String name, int userId) {
-        enforceValidUserId(userId);
-        return !hasInstallPermission(name) && hasPermission(name, userId);
-    }
-
-    /**
-     * Gets whether this state has a given install permission.
-     *
-     * @param name The permission name.
-     * @return Whether this state has the permission.
-     */
-    public boolean hasInstallPermission(String name) {
-        return hasPermission(name, UserHandle.USER_ALL);
-    }
-
-    /**
-     * Gets whether the state has a given permission for the specified
-     * user, regardless if this is an install or a runtime permission.
-     *
-     * @param name The permission name.
-     * @param userId The device user id.
-     * @return Whether the user has the permission.
-     */
-    public boolean hasPermission(String name, int userId) {
-        enforceValidUserId(userId);
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return false;
-            }
-            PermissionData permissionData = mPermissions.get(name);
-
-            return permissionData != null && permissionData.isGranted(userId);
-        }
-
-    }
-
-    /**
-     * Returns whether the state has any known request for the given permission name,
-     * whether or not it has been granted.
-     */
-    public boolean hasRequestedPermission(ArraySet<String> names) {
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return false;
-            }
-            for (int i=names.size()-1; i>=0; i--) {
-                if (mPermissions.get(names.valueAt(i)) != null) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns whether the state has any known request for the given permission name,
-     * whether or not it has been granted.
-     */
-    public boolean hasRequestedPermission(String name) {
-        return mPermissions != null && (mPermissions.get(name) != null);
-    }
-    /**
-     * Gets all permissions for a given device user id regardless if they
-     * are install time or runtime permissions.
-     *
-     * @param userId The device user id.
-     * @return The permissions or an empty set.
-     */
-    public Set<String> getPermissions(int userId) {
-        enforceValidUserId(userId);
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return Collections.emptySet();
-            }
-
-            Set<String> permissions = new ArraySet<>(mPermissions.size());
-
-            final int permissionCount = mPermissions.size();
-            for (int i = 0; i < permissionCount; i++) {
-                String permission = mPermissions.keyAt(i);
-
-                if (hasInstallPermission(permission)) {
-                    permissions.add(permission);
-                    continue;
-                }
-
-                if (userId != UserHandle.USER_ALL) {
-                    if (hasRuntimePermission(permission, userId)) {
-                        permissions.add(permission);
-                    }
-                }
-            }
-
-            return permissions;
-        }
-    }
-
-    /**
-     * Gets the state for an install permission or null if no such.
-     *
-     * @param name The permission name.
-     * @return The permission state.
-     */
-    public PermissionState getInstallPermissionState(String name) {
-        return getPermissionState(name, UserHandle.USER_ALL);
-    }
-
-    /**
-     * Gets the state for a runtime permission or null if no such.
-     *
-     * @param name The permission name.
-     * @param userId The device user id.
-     * @return The permission state.
-     */
-    public PermissionState getRuntimePermissionState(String name, int userId) {
-        enforceValidUserId(userId);
-        return getPermissionState(name, userId);
-    }
-
-    /**
-     * Gets all install permission states.
-     *
-     * @return The permission states or an empty set.
-     */
-    public List<PermissionState> getInstallPermissionStates() {
-        return getPermissionStatesInternal(UserHandle.USER_ALL);
-    }
-
-    /**
-     * Gets all runtime permission states.
-     *
-     * @return The permission states or an empty set.
-     */
-    public List<PermissionState> getRuntimePermissionStates(int userId) {
-        enforceValidUserId(userId);
-        return getPermissionStatesInternal(userId);
-    }
-
-    /**
-     * Gets the flags for a permission regardless if it is install or
-     * runtime permission.
-     *
-     * @param name The permission name.
-     * @return The permission state or null if no such.
-     */
-    public int getPermissionFlags(String name, int userId) {
-        PermissionState installPermState = getInstallPermissionState(name);
-        if (installPermState != null) {
-            return installPermState.getFlags();
-        }
-        PermissionState runtimePermState = getRuntimePermissionState(name, userId);
-        if (runtimePermState != null) {
-            return runtimePermState.getFlags();
-        }
-        return 0;
-    }
-
-    /**
-     * Update the flags associated with a given permission.
-     * @param permission The permission whose flags to update.
-     * @param userId The user for which to update.
-     * @param flagMask Mask for which flags to change.
-     * @param flagValues New values for the mask flags.
-     * @return Whether the permission flags changed.
-     */
-    public boolean updatePermissionFlags(BasePermission permission, int userId,
-            int flagMask, int flagValues) {
-        enforceValidUserId(userId);
-
-        final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                if (!mayChangeFlags) {
-                    return false;
-                }
-                ensurePermissionData(permission);
-            }
-        }
-
-        PermissionData permissionData = null;
-        synchronized (mLock) {
-            permissionData = mPermissions.get(permission.getName());
-        }
-
-        if (permissionData == null) {
-            if (!mayChangeFlags) {
-                return false;
-            }
-            permissionData = ensurePermissionData(permission);
-        }
-
-        final int oldFlags = permissionData.getFlags(userId);
-
-        final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
-        if (updated) {
-            final int newFlags = permissionData.getFlags(userId);
-            if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
-                    && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                if (mPermissionReviewRequired == null) {
-                    mPermissionReviewRequired = new SparseBooleanArray();
-                }
-                mPermissionReviewRequired.put(userId, true);
-            } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
-                    && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
-                if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) {
-                    mPermissionReviewRequired.delete(userId);
-                    if (mPermissionReviewRequired.size() <= 0) {
-                        mPermissionReviewRequired = null;
-                    }
-                }
-            }
-        }
-        return updated;
-    }
-
-    private boolean hasPermissionRequiringReview(int userId) {
-        synchronized (mLock) {
-            final int permissionCount = mPermissions.size();
-            for (int i = 0; i < permissionCount; i++) {
-                final PermissionData permission = mPermissions.valueAt(i);
-                if ((permission.getFlags(userId)
-                        & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    public boolean updatePermissionFlagsForAllPermissions(
-            int userId, int flagMask, int flagValues) {
-        enforceValidUserId(userId);
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return false;
-            }
-            boolean changed = false;
-            final int permissionCount = mPermissions.size();
-            for (int i = 0; i < permissionCount; i++) {
-                PermissionData permissionData = mPermissions.valueAt(i);
-                changed |= permissionData.updateFlags(userId, flagMask, flagValues);
-            }
-
-            return changed;
-        }
-    }
-
-    /**
-     * Compute the Linux gids for a given device user from the permissions
-     * granted to this user. Note that these are computed to avoid additional
-     * state as they are rarely accessed.
-     *
-     * @param userId The device user id.
-     * @return The gids for the device user.
-     */
-    public int[] computeGids(int userId) {
-        enforceValidUserId(userId);
-
-        int[] gids = mGlobalGids;
-
-        synchronized (mLock) {
-            if (mPermissions != null) {
-                final int permissionCount = mPermissions.size();
-                for (int i = 0; i < permissionCount; i++) {
-                    String permission = mPermissions.keyAt(i);
-                    if (!hasPermission(permission, userId)) {
-                        continue;
-                    }
-                    PermissionData permissionData = mPermissions.valueAt(i);
-                    final int[] permGids = permissionData.computeGids(userId);
-                    if (permGids != NO_GIDS) {
-                        gids = appendInts(gids, permGids);
-                    }
-                }
-            }
-        }
-
-        return gids;
-    }
-
-    /**
-     * Compute the Linux gids for all device users from the permissions
-     * granted to these users.
-     *
-     * @return The gids for all device users.
-     */
-    public int[] computeGids(int[] userIds) {
-        int[] gids = mGlobalGids;
-
-        for (int userId : userIds) {
-            final int[] userGids = computeGids(userId);
-            gids = appendInts(gids, userGids);
-        }
-
-        return gids;
-    }
-
-    /**
-     * Resets the internal state of this object.
-     */
-    public void reset() {
-        mGlobalGids = NO_GIDS;
-
-        synchronized (mLock) {
-            mPermissions = null;
-            invalidateCache();
-        }
-
-        mMissing = null;
-        mPermissionReviewRequired = null;
-    }
-
-    private PermissionState getPermissionState(String name, int userId) {
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return null;
-            }
-            PermissionData permissionData = mPermissions.get(name);
-            if (permissionData == null) {
-                return null;
-            }
-
-            return permissionData.getPermissionState(userId);
-        }
-    }
-
-    private List<PermissionState> getPermissionStatesInternal(int userId) {
-        enforceValidUserId(userId);
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return Collections.emptyList();
-            }
-
-            List<PermissionState> permissionStates = new ArrayList<>();
-
-            final int permissionCount = mPermissions.size();
-            for (int i = 0; i < permissionCount; i++) {
-                PermissionData permissionData = mPermissions.valueAt(i);
-
-                PermissionState permissionState = permissionData.getPermissionState(userId);
-                if (permissionState != null) {
-                    permissionStates.add(permissionState);
-                }
-            }
-
-            return permissionStates;
-        }
-    }
-
-    private int grantPermission(BasePermission permission, int userId) {
-        if (hasPermission(permission.getName(), userId)) {
-            return PERMISSION_OPERATION_SUCCESS;
-        }
-
-        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
-        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
-
-        PermissionData permissionData = ensurePermissionData(permission);
-
-        if (!permissionData.grant(userId)) {
-            return PERMISSION_OPERATION_FAILURE;
-        }
-
-        if (hasGids) {
-            final int[] newGids = computeGids(userId);
-            if (oldGids.length != newGids.length) {
-                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-            }
-        }
-
-        return PERMISSION_OPERATION_SUCCESS;
-    }
-
-    private int revokePermission(BasePermission permission, int userId) {
-        final String permName = permission.getName();
-        if (!hasPermission(permName, userId)) {
-            return PERMISSION_OPERATION_SUCCESS;
-        }
-
-        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
-        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
-
-        PermissionData permissionData = null;
-        synchronized (mLock) {
-            permissionData = mPermissions.get(permName);
-        }
-
-        if (!permissionData.revoke(userId)) {
-            return PERMISSION_OPERATION_FAILURE;
-        }
-
-        if (permissionData.isDefault()) {
-            ensureNoPermissionData(permName);
-        }
-
-        if (hasGids) {
-            final int[] newGids = computeGids(userId);
-            if (oldGids.length != newGids.length) {
-                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-            }
-        }
-
-        return PERMISSION_OPERATION_SUCCESS;
-    }
-
-    // TODO: fix this to use arraycopy and append all ints in one go
-    private static int[] appendInts(int[] current, int[] added) {
-        if (current != null && added != null) {
-            for (int guid : added) {
-                current = ArrayUtils.appendInt(current, guid);
-            }
-        }
-        return current;
-    }
-
-    private static void enforceValidUserId(int userId) {
-        if (userId != UserHandle.USER_ALL && userId < 0) {
-            throw new IllegalArgumentException("Invalid userId:" + userId);
-        }
-    }
-
-    private PermissionData ensurePermissionData(BasePermission permission) {
-        final String permName = permission.getName();
-
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                mPermissions = new ArrayMap<>();
-            }
-            PermissionData permissionData = mPermissions.get(permName);
-            if (permissionData == null) {
-                permissionData = new PermissionData(permission);
-                mPermissions.put(permName, permissionData);
-            }
-            return permissionData;
-        }
-
-    }
-
-    private void ensureNoPermissionData(String name) {
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return;
-            }
-            mPermissions.remove(name);
-            if (mPermissions.isEmpty()) {
-                mPermissions = null;
-            }
-        }
-
-    }
-
-    private static final class PermissionData {
-
-        private final Object mLock = new Object();
-
-        private final BasePermission mPerm;
-        @GuardedBy("mLock")
-        private SparseArray<PermissionState> mUserStates = new SparseArray<>();
-
-        public PermissionData(BasePermission perm) {
-            mPerm = perm;
-        }
-
-        public PermissionData(PermissionData other) {
-            this(other.mPerm);
-
-            synchronized (mLock) {
-                final int otherStateCount = other.mUserStates.size();
-                for (int i = 0; i < otherStateCount; i++) {
-                    final int otherUserId = other.mUserStates.keyAt(i);
-                    PermissionState otherState = other.mUserStates.valueAt(i);
-                    mUserStates.put(otherUserId, new PermissionState(otherState));
-                }
-            }
-        }
-
-        public int[] computeGids(int userId) {
-            return mPerm.computeGids(userId);
-        }
-
-        public boolean isGranted(int userId) {
-            synchronized (mLock) {
-                if (isInstallPermission()) {
-                    userId = UserHandle.USER_ALL;
-                }
-
-                PermissionState userState = mUserStates.get(userId);
-                if (userState == null) {
-                    return false;
-                }
-
-                return userState.mGranted;
-            }
-        }
-
-        public boolean grant(int userId) {
-            synchronized (mLock) {
-                if (!isCompatibleUserId(userId)) {
-                    return false;
-                }
-
-                if (isGranted(userId)) {
-                    return false;
-                }
-
-                PermissionState userState = mUserStates.get(userId);
-                if (userState == null) {
-                    userState = new PermissionState(mPerm);
-                    mUserStates.put(userId, userState);
-                }
-
-                userState.mGranted = true;
-
-                invalidateCache();
-                return true;
-            }
-        }
-
-        public boolean revoke(int userId) {
-            synchronized (mLock) {
-                if (!isCompatibleUserId(userId)) {
-                    return false;
-                }
-
-                if (!isGranted(userId)) {
-                    return false;
-                }
-
-                PermissionState userState = mUserStates.get(userId);
-                userState.mGranted = false;
-
-                if (userState.isDefault()) {
-                    mUserStates.remove(userId);
-                }
-
-                invalidateCache();
-                return true;
-            }
-        }
-
-        public PermissionState getPermissionState(int userId) {
-            synchronized (mLock) {
-                return mUserStates.get(userId);
-            }
-        }
-
-        public int getFlags(int userId) {
-            synchronized (mLock) {
-                PermissionState userState = mUserStates.get(userId);
-                if (userState != null) {
-                    return userState.mFlags;
-                }
-                return 0;
-            }
-        }
-
-        public boolean isDefault() {
-            synchronized (mLock) {
-                return mUserStates.size() <= 0;
-            }
-        }
-
-        public static boolean isInstallPermissionKey(int userId) {
-            return userId == UserHandle.USER_ALL;
-        }
-
-        public boolean updateFlags(int userId, int flagMask, int flagValues) {
-            synchronized (mLock) {
-                if (isInstallPermission()) {
-                    userId = UserHandle.USER_ALL;
-                }
-
-                if (!isCompatibleUserId(userId)) {
-                    return false;
-                }
-
-                final int newFlags = flagValues & flagMask;
-
-                // Okay to do before the modification because we hold the lock.
-                invalidateCache();
-
-                PermissionState userState = mUserStates.get(userId);
-                if (userState != null) {
-                    final int oldFlags = userState.mFlags;
-                    userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
-                    if (userState.isDefault()) {
-                        mUserStates.remove(userId);
-                    }
-                    return userState.mFlags != oldFlags;
-                } else if (newFlags != 0) {
-                    userState = new PermissionState(mPerm);
-                    userState.mFlags = newFlags;
-                    mUserStates.put(userId, userState);
-                    return true;
-                }
-
-                return false;
-            }
-        }
-
-        private boolean isCompatibleUserId(int userId) {
-            return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
-        }
-
-        private boolean isInstallPermission() {
-            return mUserStates.size() == 1
-                    && mUserStates.get(UserHandle.USER_ALL) != null;
-        }
-    }
-
-    public static final class PermissionState {
-        private final BasePermission mPermission;
-        private boolean mGranted;
-        private int mFlags;
-
-        public PermissionState(BasePermission permission) {
-            mPermission = permission;
-        }
-
-        public PermissionState(PermissionState other) {
-            mPermission = other.mPermission;
-            mGranted = other.mGranted;
-            mFlags = other.mFlags;
-        }
-
-        public boolean isDefault() {
-            return !mGranted && mFlags == 0;
-        }
-
-        public BasePermission getPermission() {
-            return mPermission;
-        }
-
-        public String getName() {
-            return mPermission.getName();
-        }
-
-        public boolean isGranted() {
-            return mGranted;
-        }
-
-        public int getFlags() {
-            return mFlags;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/pm/permission/UidPermissionState.java b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
index 4c047ff..b45176b 100644
--- a/services/core/java/com/android/server/pm/permission/UidPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/UidPermissionState.java
@@ -207,23 +207,6 @@
     }
 
     /**
-     * Gets whether the state has a given install permission.
-     *
-     * @param name The permission name.
-     * @return Whether the state has the install permission.
-     */
-    public boolean hasInstallPermission(@NonNull String name) {
-        synchronized (mLock) {
-            if (mPermissions == null) {
-                return false;
-            }
-            PermissionState permissionState = mPermissions.get(name);
-            return permissionState != null && permissionState.isGranted()
-                    && !permissionState.isRuntime();
-        }
-    }
-
-    /**
      * Returns whether the state has any known request for the given permission name,
      * whether or not it has been granted.
      *
@@ -459,11 +442,11 @@
     /**
      * Put a permission state.
      */
-    public void putPermissionState(@NonNull BasePermission permission, boolean isRuntime,
-            boolean isGranted, int flags) {
+    public void putPermissionState(@NonNull BasePermission permission, boolean isGranted,
+            int flags) {
         synchronized (mLock) {
             ensureNoPermissionState(permission.name);
-            PermissionState permissionState = ensurePermissionState(permission, isRuntime);
+            PermissionState permissionState = ensurePermissionState(permission);
             if (isGranted) {
                 permissionState.grant();
             }
@@ -540,12 +523,6 @@
 
     @NonNull
     private PermissionState ensurePermissionState(@NonNull BasePermission permission) {
-        return ensurePermissionState(permission, permission.isRuntime());
-    }
-
-    @NonNull
-    private PermissionState ensurePermissionState(@NonNull BasePermission permission,
-            boolean isRuntime) {
         final String permissionName = permission.getName();
         synchronized (mLock) {
             if (mPermissions == null) {
@@ -553,7 +530,7 @@
             }
             PermissionState permissionState = mPermissions.get(permissionName);
             if (permissionState == null) {
-                permissionState = new PermissionState(permission, isRuntime);
+                permissionState = new PermissionState(permission);
                 mPermissions.put(permissionName, permissionState);
             }
             return permissionState;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index 1d31285..de8823c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -40,7 +40,10 @@
 import android.media.soundtrigger_middleware.SoundModelType;
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
 import android.os.HidlMemoryUtil;
+import android.os.ParcelFileDescriptor;
 
+import java.io.FileDescriptor;
+import java.io.IOException;
 import java.util.regex.Matcher;
 
 /**
@@ -196,8 +199,18 @@
         hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type);
         hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid);
         hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid);
-        hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(aidlModel.data,
-                aidlModel.dataSize);
+
+        // Extract a dup of the underlying FileDescriptor out of aidlModel.data without changing
+        // the original.
+        FileDescriptor fd = new FileDescriptor();
+        try {
+            ParcelFileDescriptor dup = aidlModel.data.dup();
+            fd.setInt$(dup.detachFd());
+            hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(fd, aidlModel.dataSize);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+
         return hidlModel;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 740b592..6792430 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4770,14 +4770,14 @@
                     supportsEnterPipOnTaskSwitch = false;
                     break;
                 case RESUMED:
-                    // Do nothing if currently in the process of resuming the activity. Otherwise,
-                    // starting to pause it since it is not visible.
-                    if (!mSetToSleep) {
+                    // If the app is capable of entering PIP, we should try pausing it now
+                    // so it can PIP correctly.
+                    if (deferHidingClient) {
+                        getRootTask().startPausingLocked(
+                                mStackSupervisor.mUserLeaving /* userLeaving */,
+                                false /* uiSleeping */, null /* resuming */, "makeInvisible");
                         break;
                     }
-                    getRootTask().startPausingLocked(mStackSupervisor.mUserLeaving,
-                            false /* uiSleeping */, null /* resuming */, "makeInvisible");
-                    // fall through
                 case INITIALIZING:
                 case PAUSING:
                 case PAUSED:
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index ab46450..f7fd6ec 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -731,6 +731,11 @@
         final Task rootTask = task.getRootTask();
 
         beginDeferResume();
+        // The LaunchActivityItem also contains process configuration, so the configuration change
+        // from WindowProcessController#setProcess can be deferred. The major reason is that if
+        // the activity has FixedRotationAdjustments, it needs to be applied with configuration.
+        // In general, this reduces a binder transaction if process configuration is changed.
+        proc.pauseConfigurationDispatch();
 
         try {
             r.startFreezingScreenLocked(proc, 0);
@@ -824,9 +829,9 @@
                 // Because we could be starting an Activity in the system process this may not go
                 // across a Binder interface which would create a new Configuration. Consequently
                 // we have to always create a new Configuration here.
-
+                final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity();
                 final MergedConfiguration mergedConfiguration = new MergedConfiguration(
-                        proc.getConfiguration(), r.getMergedOverrideConfiguration());
+                        procConfig, r.getMergedOverrideConfiguration());
                 r.setLastReportedConfiguration(mergedConfiguration);
 
                 logIfTransactionTooLarge(r.intent, r.getSavedState());
@@ -860,6 +865,11 @@
                 // Schedule transaction.
                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);
 
+                if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) {
+                    // If the seq is increased, there should be something changed (e.g. registered
+                    // activity configuration).
+                    proc.setLastReportedConfiguration(procConfig);
+                }
                 if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mHasHeavyWeightFeature) {
                     // This may be a heavy-weight process! Note that the package manager will ensure
@@ -894,6 +904,7 @@
             }
         } finally {
             endDeferResume();
+            proc.resumeConfigurationDispatch();
         }
 
         r.launchFailed = false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e8e4059..fa4373f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -700,11 +700,15 @@
                     mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
                 }
 
+                // The original options may have additional info about metrics. The mOptions is not
+                // used here because it may be cleared in setTargetStackIfNeeded.
+                final ActivityOptions originalOptions = mRequest.activityOptions != null
+                        ? mRequest.activityOptions.getOriginalOptions() : null;
                 // Notify ActivityMetricsLogger that the activity has launched.
                 // ActivityMetricsLogger will then wait for the windows to be drawn and populate
                 // WaitResult.
                 mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
-                        mLastStartActivityRecord, mOptions);
+                        mLastStartActivityRecord, originalOptions);
                 return getExternalResult(mRequest.waitResult == null ? res
                         : waitForResult(res, mLastStartActivityRecord));
             }
@@ -1493,9 +1497,10 @@
             // anyone interested in this piece of information.
             final Task homeStack = targetTask.getDisplayArea().getRootHomeTask();
             final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+            final ActivityRecord top = targetTask.getTopNonFinishingActivity();
+            final boolean visible = top != null && top.isVisible();
             mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
-                    targetTask.getTaskInfo(), homeTaskVisible, clearedTask,
-                    targetTask.getTopNonFinishingActivity().isVisible());
+                    targetTask.getTaskInfo(), homeTaskVisible, clearedTask, visible);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 6305fda..958a7a8 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -16,9 +16,13 @@
 
 package com.android.server.wm;
 
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
+
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import com.android.internal.protolog.common.ProtoLog;
+
 import java.util.Set;
 
 /**
@@ -63,25 +67,38 @@
 
         private void tryFinish() {
             if (mRemainingTransactions == 0 && mReady) {
+                ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Finished. Reporting %d "
+                        + "containers to %s", BLASTSyncEngine.this.hashCode(), mSyncId,
+                        mWindowContainersReady.size(), mListener);
                 mListener.onTransactionReady(mSyncId, mWindowContainersReady);
                 mPendingSyncs.remove(mSyncId);
             }
         }
 
-        public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
+        public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
             mRemainingTransactions--;
+            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Child ready, now ready=%b"
+                    + " and waiting on %d transactions", BLASTSyncEngine.this.hashCode(), mSyncId,
+                    mReady, mRemainingTransactions);
             mWindowContainersReady.addAll(windowContainersReady);
             tryFinish();
         }
 
         void setReady() {
+            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Set ready",
+                    BLASTSyncEngine.this.hashCode(), mSyncId);
             mReady = true;
             tryFinish();
         }
 
         boolean addToSync(WindowContainer wc) {
+            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Trying to add %s",
+                    BLASTSyncEngine.this.hashCode(), mSyncId, wc);
             if (wc.prepareForSync(this, mSyncId)) {
                 mRemainingTransactions++;
+                ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Added %s. now waiting "
+                        + "on %d transactions", BLASTSyncEngine.this.hashCode(), mSyncId, wc,
+                        mRemainingTransactions);
                 return true;
             }
             return false;
@@ -105,6 +122,7 @@
         final int id = mNextSyncId++;
         final SyncState s = new SyncState(listener, id);
         mPendingSyncs.put(id, s);
+        ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Start for %s", hashCode(), id, listener);
         return id;
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 01c007e..dd92f507 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -52,10 +52,7 @@
         public void binderDied() {
             synchronized (mGlobalLock) {
                 mOrganizersByFeatureIds.remove(mFeature);
-                mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
-                    if (da.mOrganizer != mOrganizer) return;
-                    da.setOrganizer(null);
-                });
+                removeOrganizer(mOrganizer);
             }
         }
     }
@@ -112,11 +109,7 @@
                         organizer.asBinder(), uid);
                 mOrganizersByFeatureIds.entrySet().removeIf(
                         entry -> entry.getValue().asBinder() == organizer.asBinder());
-
-                mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
-                    if (da.mOrganizer != organizer) return;
-                    da.setOrganizer(null);
-                });
+                removeOrganizer(organizer);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -151,4 +144,13 @@
             // Oh well...
         }
     }
+
+    private void removeOrganizer(IDisplayAreaOrganizer organizer) {
+        IBinder organizerBinder = organizer.asBinder();
+        mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
+            if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
+                da.setOrganizer(null);
+            }
+        });
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0be5cbe..b3e69d4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1849,7 +1849,8 @@
         final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
         final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
         final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
-        outConfig.windowConfiguration.getBounds().set(0, 0, dw, dh);
+        outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);
+        outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());
 
         final int uiMode = getConfiguration().uiMode;
         final DisplayCutout displayCutout =
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 572c9b3..6fffde1 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -649,7 +649,7 @@
 
         mRefreshRatePolicy = new RefreshRatePolicy(mService,
                 mDisplayContent.getDisplayInfo(),
-                mService.mHighRefreshRateBlacklist);
+                mService.mHighRefreshRateDenylist);
 
         mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
                 mContext, () -> {
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
similarity index 74%
rename from services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
rename to services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index aac6b25..cdc14cd 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -34,62 +34,62 @@
 /**
  * A Denylist for packages that should force the display out of high refresh rate.
  */
-class HighRefreshRateBlacklist {
+class HighRefreshRateDenylist {
 
-    private final ArraySet<String> mBlacklistedPackages = new ArraySet<>();
+    private final ArraySet<String> mDenylistedPackages = new ArraySet<>();
     @NonNull
-    private final String[] mDefaultBlacklist;
+    private final String[] mDefaultDenylist;
     private final Object mLock = new Object();
 
     private DeviceConfigInterface mDeviceConfig;
     private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener();
 
-    static HighRefreshRateBlacklist create(@NonNull Resources r) {
-        return new HighRefreshRateBlacklist(r, DeviceConfigInterface.REAL);
+    static HighRefreshRateDenylist create(@NonNull Resources r) {
+        return new HighRefreshRateDenylist(r, DeviceConfigInterface.REAL);
     }
 
     @VisibleForTesting
-    HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) {
-        mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
+    HighRefreshRateDenylist(Resources r, DeviceConfigInterface deviceConfig) {
+        mDefaultDenylist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
         mDeviceConfig = deviceConfig;
         mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                 BackgroundThread.getExecutor(), mListener);
         final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                 KEY_HIGH_REFRESH_RATE_BLACKLIST);
-        updateBlacklist(property);
+        updateDenylist(property);
     }
 
-    private void updateBlacklist(@Nullable String property) {
+    private void updateDenylist(@Nullable String property) {
         synchronized (mLock) {
-            mBlacklistedPackages.clear();
+            mDenylistedPackages.clear();
             if (property != null) {
                 String[] packages = property.split(",");
                 for (String pkg : packages) {
                     String pkgName = pkg.trim();
                     if (!pkgName.isEmpty()) {
-                        mBlacklistedPackages.add(pkgName);
+                        mDenylistedPackages.add(pkgName);
                     }
                 }
             } else {
                 // If there's no config, or the config has been deleted, fallback to the device's
                 // default denylist
-                for (String pkg : mDefaultBlacklist) {
-                    mBlacklistedPackages.add(pkg);
+                for (String pkg : mDefaultDenylist) {
+                    mDenylistedPackages.add(pkg);
                 }
             }
         }
     }
 
-    boolean isBlacklisted(String packageName) {
+    boolean isDenylisted(String packageName) {
         synchronized (mLock) {
-            return mBlacklistedPackages.contains(packageName);
+            return mDenylistedPackages.contains(packageName);
         }
     }
     void dump(PrintWriter pw) {
-        pw.println("High Refresh Rate Blacklist");
+        pw.println("High Refresh Rate Denylist");
         pw.println("  Packages:");
         synchronized (mLock) {
-            for (String pkg : mBlacklistedPackages) {
+            for (String pkg : mDenylistedPackages) {
                 pw.println("    " + pkg);
             }
         }
@@ -100,13 +100,13 @@
     void dispose() {
         mDeviceConfig.removeOnPropertiesChangedListener(mListener);
         mDeviceConfig = null;
-        mBlacklistedPackages.clear();
+        mDenylistedPackages.clear();
     }
 
     private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
         public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
             if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) {
-                updateBlacklist(
+                updateDenylist(
                         properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/));
             }
         }
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 072116f..91014aa 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -30,7 +30,7 @@
 
     private final int mLowRefreshRateId;
     private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
-    private final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
+    private final HighRefreshRateDenylist mHighRefreshRateDenylist;
     private final WindowManagerService mWmService;
 
     /**
@@ -55,9 +55,9 @@
     static final int LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
 
     RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
-            HighRefreshRateBlacklist blacklist) {
+            HighRefreshRateDenylist denylist) {
         mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
-        mHighRefreshRateBlacklist = blacklist;
+        mHighRefreshRateDenylist = denylist;
         mWmService = wmService;
     }
 
@@ -108,7 +108,7 @@
         }
 
         // If app is denylisted using higher refresh rate, return default (lower) refresh rate
-        if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) {
+        if (mHighRefreshRateDenylist.isDenylisted(packageName)) {
             return mLowRefreshRateId;
         }
         return 0;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d149db6..71ecf72 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -76,6 +76,7 @@
 import static com.android.server.wm.Task.ActivityState.STOPPING;
 import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -1907,22 +1908,33 @@
     }
 
     boolean attachApplication(WindowProcessController app) throws RemoteException {
-        final String processName = app.mName;
         boolean didSomething = false;
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
-            final DisplayContent display = getChildAt(displayNdx);
-            final Task stack = display.getFocusedStack();
-            if (stack == null) {
-                continue;
-            }
-
             mTmpRemoteException = null;
             mTmpBoolean = false; // Set to true if an activity was started.
-            final PooledFunction c = PooledLambda.obtainFunction(
-                    RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
-                    PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivity());
-            stack.forAllActivities(c);
-            c.recycle();
+            final DisplayContent display = getChildAt(displayNdx);
+            display.forAllTaskDisplayAreas(displayArea -> {
+                if (mTmpRemoteException != null) {
+                    return;
+                }
+
+                for (int taskNdx = displayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
+                    final Task rootTask = displayArea.getStackAt(taskNdx);
+                    if (rootTask.getVisibility(null /*starting*/) == STACK_VISIBILITY_INVISIBLE) {
+                        break;
+                    }
+
+                    final PooledFunction c = PooledLambda.obtainFunction(
+                            RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
+                            PooledLambda.__(ActivityRecord.class), app,
+                            rootTask.topRunningActivity());
+                    rootTask.forAllActivities(c);
+                    c.recycle();
+                    if (mTmpRemoteException != null) {
+                        return;
+                    }
+                }
+            });
             if (mTmpRemoteException != null) {
                 throw mTmpRemoteException;
             }
@@ -1942,8 +1954,8 @@
         }
 
         try {
-            if (mStackSupervisor.realStartActivityLocked(r, app, top == r /*andResume*/,
-                    true /*checkConfig*/)) {
+            if (mStackSupervisor.realStartActivityLocked(r, app,
+                    top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/)) {
                 mTmpBoolean = true;
             }
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index ede6708..9205401 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -150,6 +150,14 @@
     }
 
     /**
+     * Gets the original options passed in. It should only be used for logging. DO NOT use it as a
+     * condition in the logic of activity launch.
+     */
+    ActivityOptions getOriginalOptions() {
+        return mOriginalOptions;
+    }
+
+    /**
      * @see ActivityOptions#popAppVerificationBundle
      */
     Bundle popAppVerificationBundle() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2a0488d..ce602de 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -318,6 +318,7 @@
     // Do not move the stack as a part of reparenting
     static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
 
+    // TODO (b/157876447): switch to Task related name
     @IntDef(prefix = {"STACK_VISIBILITY"}, value = {
             STACK_VISIBILITY_VISIBLE,
             STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
@@ -4112,6 +4113,10 @@
             return STACK_VISIBILITY_INVISIBLE;
         }
 
+        if (isTopActivityLaunchedBehind()) {
+            return STACK_VISIBILITY_VISIBLE;
+        }
+
         boolean gotSplitScreenStack = false;
         boolean gotOpaqueSplitScreenPrimary = false;
         boolean gotOpaqueSplitScreenSecondary = false;
@@ -4229,6 +4234,14 @@
                 : STACK_VISIBILITY_VISIBLE;
     }
 
+    private boolean isTopActivityLaunchedBehind() {
+        final ActivityRecord top = topRunningActivity();
+        if (top != null && top.mLaunchTaskBehind) {
+            return true;
+        }
+        return false;
+    }
+
     ActivityRecord isInTask(ActivityRecord r) {
         if (r == null) {
             return null;
@@ -6039,8 +6052,9 @@
         // If the most recent activity was noHistory but was only stopped rather
         // than stopped+finished because the device went to sleep, we need to make
         // sure to finish it as we're making a new activity topmost.
-        if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
-                !mLastNoHistoryActivity.finishing) {
+        if (shouldSleepActivities() && mLastNoHistoryActivity != null
+                && !mLastNoHistoryActivity.finishing
+                && mLastNoHistoryActivity != next) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "no-history finish of " + mLastNoHistoryActivity + " on new resume");
             mLastNoHistoryActivity.finishIfPossible("resume-no-history", false /* oomAdj */);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index c11624c..76bd6ce 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -151,6 +151,12 @@
      */
     private boolean mRemoved;
 
+    /**
+     * Whether the task display area should ignore fixed-orientation request. If {@code true}, it
+     * can never specify orientation, but show the fixed-orientation apps in the letterbox;
+     * otherwise, it rotates based on the fixed-orientation request when it has the focus.
+     */
+    private boolean mIgnoreOrientationRequest;
 
     /**
      * The id of a leaf task that most recently being moved to front.
@@ -641,11 +647,30 @@
         }
     }
 
+    /**
+     * Sets whether the task display area should ignore fixed-orientation request from apps.
+     * @return Whether the display orientation changed
+     */
+    boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) {
+        if (mIgnoreOrientationRequest == ignoreOrientationRequest) {
+            return false;
+        }
+
+        mIgnoreOrientationRequest = ignoreOrientationRequest;
+        if (isLastFocused()) {
+            // Update orientation if this TDA is the last focused, otherwise it shouldn't affect
+            // the display.
+            return mDisplayContent.updateOrientation();
+        }
+
+        return false;
+    }
+
     @Override
     int getOrientation(int candidate) {
-        // Only allow to specify orientation if this TDA has the focus.
-        // TODO(b/155431879) Add option to never allow a TDA to specify orientation.
-        if (!isLastFocused()) {
+        // Only allow to specify orientation if this TDA is not set to ignore orientation request,
+        // and it has the focus.
+        if (mIgnoreOrientationRequest || !isLastFocused()) {
             return SCREEN_ORIENTATION_UNSET;
         }
 
@@ -1571,10 +1596,12 @@
         return topRunning;
     }
 
+    // TODO (b/157876447): switch to Task related name
     protected int getStackCount() {
         return mChildren.size();
     }
 
+    // TODO (b/157876447): switch to Task related name
     protected Task getStackAt(int index) {
         return mChildren.get(index);
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ae8f7a5..2b93080 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -32,6 +32,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -2886,6 +2887,8 @@
         // If we are invisible, no need to sync, likewise if we are already engaged in a sync,
         // we can't support overlapping syncs on a single container yet.
         if (!isVisible() || mWaitingListener != null) {
+            ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "- NOT adding to sync: visible=%b "
+                            + "hasListener=%b", isVisible(), mWaitingListener != null);
             return false;
         }
         mUsingBLASTSyncTransaction = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4519916..d9c574c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1005,7 +1005,7 @@
 
     final Configuration mTempConfiguration = new Configuration();
 
-    final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
+    final HighRefreshRateDenylist mHighRefreshRateDenylist;
 
     // If true, only the core apps and services are being launched because the device
     // is in a special boot mode, such as being encrypted or waiting for a decryption password.
@@ -1302,7 +1302,7 @@
                 this, mInputManager, mActivityTaskManager, mH.getLooper());
         mDragDropController = new DragDropController(this, mH.getLooper());
 
-        mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
+        mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources());
 
         mConstants = new WindowManagerConstants(this, DeviceConfigInterface.REAL);
         mConstants.start(new HandlerExecutor(mH));
@@ -5939,7 +5939,7 @@
 
     private void dumpHighRefreshRateBlacklist(PrintWriter pw) {
         pw.println("WINDOW MANAGER HIGH REFRESH RATE BLACKLIST (dumpsys window refresh)");
-        mHighRefreshRateBlacklist.dump(pw);
+        mHighRefreshRateDenylist.dump(pw);
     }
 
     private void dumpTraceStatus(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index c7cad2f..999181d 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -306,6 +306,19 @@
         return effects;
     }
 
+    private int applyTaskDisplayAreaChanges(TaskDisplayArea taskDisplayArea,
+            WindowContainerTransaction.Change c) {
+        int effects = applyDisplayAreaChanges(taskDisplayArea, c);
+        if ((c.getChangeMask()
+                & WindowContainerTransaction.Change.CHANGE_IGNORE_ORIENTATION_REQUEST) != 0) {
+            if (taskDisplayArea.setIgnoreOrientationRequest(c.getIgnoreOrientationRequest())) {
+                effects |= TRANSACT_EFFECTS_LIFECYCLE;
+            }
+        }
+
+        return effects;
+    }
+
     private int applyDisplayAreaChanges(WindowContainer container,
             WindowContainerTransaction.Change c) {
         final int[] effects = new int[1];
@@ -388,7 +401,9 @@
 
         int effects = applyChanges(wc, c);
 
-        if (wc instanceof DisplayArea) {
+        if (wc instanceof TaskDisplayArea) {
+            effects |= applyTaskDisplayAreaChanges((TaskDisplayArea) wc, c);
+        } else if (wc instanceof DisplayArea) {
             effects |= applyDisplayAreaChanges(wc, c);
         } else if (wc instanceof Task) {
             effects |= applyTaskChanges(wc.asTask(), c);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 59f209a..268281b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -194,13 +194,16 @@
 
     // Last configuration that was reported to the process.
     private final Configuration mLastReportedConfiguration = new Configuration();
-    // Configuration that is waiting to be dispatched to the process.
-    private Configuration mPendingConfiguration;
+    /** Whether the process configuration is waiting to be dispatched to the process. */
+    private boolean mHasPendingConfigurationChange;
     // Registered display id as a listener to override config change
     private int mDisplayId;
     private ActivityRecord mConfigActivityRecord;
     // Whether the activity config override is allowed for this process.
     private volatile boolean mIsActivityConfigOverrideAllowed = true;
+    /** Non-zero to pause dispatching process configuration change. */
+    private int mPauseConfigurationDispatchCount;
+
     /**
      * Activities that hosts some UI drawn by the current process. The activities live
      * in another process. This is used to check if the process is currently showing anything
@@ -1243,8 +1246,10 @@
         onMergedOverrideConfigurationChanged(Configuration.EMPTY);
     }
 
-    private void registerActivityConfigurationListener(ActivityRecord activityRecord) {
-        if (activityRecord == null || activityRecord.containsListener(this)) {
+    void registerActivityConfigurationListener(ActivityRecord activityRecord) {
+        if (activityRecord == null || activityRecord.containsListener(this)
+                // Check for the caller from outside of this class.
+                || !mIsActivityConfigOverrideAllowed) {
             return;
         }
         // A process can only register to one activityRecord to listen to the override configuration
@@ -1296,25 +1301,25 @@
 
     @Override
     public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        super.onRequestedOverrideConfigurationChanged(
-                sanitizeProcessConfiguration(overrideConfiguration));
+        super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
     }
 
     @Override
     public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) {
-        super.onRequestedOverrideConfigurationChanged(
-                sanitizeProcessConfiguration(mergedOverrideConfig));
+        super.onRequestedOverrideConfigurationChanged(mergedOverrideConfig);
     }
 
-    private static Configuration sanitizeProcessConfiguration(Configuration config) {
+    @Override
+    void resolveOverrideConfiguration(Configuration newParentConfig) {
+        super.resolveOverrideConfiguration(newParentConfig);
+        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
         // Make sure that we don't accidentally override the activity type.
-        if (config.windowConfiguration.getActivityType() != ACTIVITY_TYPE_UNDEFINED) {
-            final Configuration sanitizedConfig = new Configuration(config);
-            sanitizedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
-            return sanitizedConfig;
-        }
-
-        return config;
+        resolvedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+        // Activity has an independent ActivityRecord#mConfigurationSeq. If this process registers
+        // activity configuration, its config seq shouldn't go backwards by activity configuration.
+        // Otherwise if other places send wpc.getConfiguration() to client, the configuration may
+        // be ignored due to the seq is older.
+        resolvedConfig.seq = newParentConfig.seq;
     }
 
     private void updateConfiguration() {
@@ -1332,11 +1337,7 @@
         if (mListener.isCached()) {
             // This process is in a cached state. We will delay delivering the config change to the
             // process until the process is no longer cached.
-            if (mPendingConfiguration == null) {
-                mPendingConfiguration = new Configuration(config);
-            } else {
-                mPendingConfiguration.setTo(config);
-            }
+            mHasPendingConfigurationChange = true;
             return;
         }
 
@@ -1344,6 +1345,11 @@
     }
 
     private void dispatchConfigurationChange(Configuration config) {
+        if (mPauseConfigurationDispatchCount > 0) {
+            mHasPendingConfigurationChange = true;
+            return;
+        }
+        mHasPendingConfigurationChange = false;
         if (mThread == null) {
             if (Build.IS_DEBUGGABLE && mHasImeService) {
                 // TODO (b/135719017): Temporary log for debugging IME service.
@@ -1369,7 +1375,7 @@
         }
     }
 
-    private void setLastReportedConfiguration(Configuration config) {
+    void setLastReportedConfiguration(Configuration config) {
         mLastReportedConfiguration.setTo(config);
     }
 
@@ -1377,6 +1383,30 @@
         return mLastReportedConfiguration;
     }
 
+    void pauseConfigurationDispatch() {
+        mPauseConfigurationDispatchCount++;
+    }
+
+    void resumeConfigurationDispatch() {
+        mPauseConfigurationDispatchCount--;
+    }
+
+    /**
+     * This is called for sending {@link android.app.servertransaction.LaunchActivityItem}.
+     * The caller must call {@link #setLastReportedConfiguration} if the delivered configuration
+     * is newer.
+     */
+    Configuration prepareConfigurationForLaunchingActivity() {
+        final Configuration config = getConfiguration();
+        if (mHasPendingConfigurationChange) {
+            mHasPendingConfigurationChange = false;
+            // The global configuration may not change, so the client process may have the same
+            // config seq. This increment ensures that the client won't ignore the configuration.
+            config.seq = mAtm.increaseConfigurationSeqLocked();
+        }
+        return config;
+    }
+
     /** Returns the total time (in milliseconds) spent executing in both user and system code. */
     public long getCpuTime() {
         return (mListener != null) ? mListener.getCpuTime() : 0;
@@ -1468,10 +1498,8 @@
     public void onProcCachedStateChanged(boolean isCached) {
         if (!isCached) {
             synchronized (mAtm.mGlobalLockWithoutBoost) {
-                if (mPendingConfiguration != null) {
-                    final Configuration config = mPendingConfiguration;
-                    mPendingConfiguration = null;
-                    dispatchConfigurationChange(config);
+                if (mHasPendingConfigurationChange) {
+                    dispatchConfigurationChange(getConfiguration());
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5e81400..029c158 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -441,10 +441,6 @@
             return mSurfaceController;
         }
 
-        if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
-            windowType = SurfaceControl.WINDOW_TYPE_DONT_SCREENSHOT;
-        }
-
         w.setHasSurface(false);
 
         if (DEBUG_ANIM) {
@@ -462,6 +458,10 @@
             flags |= SurfaceControl.SECURE;
         }
 
+        if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
+            flags |= SurfaceControl.SKIP_SCREENSHOT;
+        }
+
         calculateSurfaceBounds(w, attrs, mTmpSize);
         final int width = mTmpSize.width();
         final int height = mTmpSize.height();
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index bc4d9a9..fa0b8cc 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -181,6 +181,12 @@
                 }
             }
         }
+
+        /** The state may not only be used by self. Make sure to leave the influence by others. */
+        void disassociate(WindowToken token) {
+            mAssociatedTokens.remove(token);
+            mRotatedContainers.remove(token);
+        }
     }
 
     private class DeathRecipient implements IBinder.DeathRecipient {
@@ -548,7 +554,7 @@
     void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
             Configuration config) {
         if (mFixedRotationTransformState != null) {
-            cleanUpFixedRotationTransformState(true /* replacing */);
+            mFixedRotationTransformState.disassociate(this);
         }
         mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
                 new Configuration(config), mDisplayContent.getRotation());
@@ -556,8 +562,7 @@
         mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames,
                 mFixedRotationTransformState.mInsetsState,
                 mFixedRotationTransformState.mBarContentFrames);
-        onConfigurationChanged(getParent().getConfiguration());
-        notifyFixedRotationTransform(true /* enabled */);
+        onFixedRotationStatePrepared();
     }
 
     /**
@@ -570,12 +575,29 @@
             return;
         }
         if (mFixedRotationTransformState != null) {
-            cleanUpFixedRotationTransformState(true /* replacing */);
+            mFixedRotationTransformState.disassociate(this);
         }
         mFixedRotationTransformState = fixedRotationState;
         fixedRotationState.mAssociatedTokens.add(this);
-        onConfigurationChanged(getParent().getConfiguration());
+        onFixedRotationStatePrepared();
+    }
+
+    /**
+     * Makes the rotated states take effect for this window container and its client process.
+     * This should only be called when {@link #mFixedRotationTransformState} is non-null.
+     */
+    private void onFixedRotationStatePrepared() {
+        // Send the adjustment info first so when the client receives configuration change, it can
+        // get the rotated display metrics.
         notifyFixedRotationTransform(true /* enabled */);
+        // Resolve the rotated configuration.
+        onConfigurationChanged(getParent().getConfiguration());
+        final ActivityRecord r = asActivityRecord();
+        if (r != null && r.hasProcess()) {
+            // The application needs to be configured as in a rotated environment for compatibility.
+            // This registration will send the rotated configuration to its process.
+            r.app.registerActivityConfigurationListener(r);
+        }
     }
 
     /**
@@ -626,21 +648,12 @@
         // The state is cleared at the end, because it is used to indicate that other windows can
         // use seamless rotation when applying rotation to display.
         for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
-            state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(
-                    false /* replacing */);
+            final WindowToken token = state.mAssociatedTokens.get(i);
+            token.mFixedRotationTransformState = null;
+            token.notifyFixedRotationTransform(false /* enabled */);
         }
     }
 
-    private void cleanUpFixedRotationTransformState(boolean replacing) {
-        if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) {
-            // The state is not only used by self. Make sure to leave the influence by others.
-            mFixedRotationTransformState.mAssociatedTokens.remove(this);
-            mFixedRotationTransformState.mRotatedContainers.remove(this);
-        }
-        mFixedRotationTransformState = null;
-        notifyFixedRotationTransform(false /* enabled */);
-    }
-
     /** Notifies application side to enable or disable the rotation adjustment of display info. */
     private void notifyFixedRotationTransform(boolean enabled) {
         FixedRotationAdjustments adjustments = null;
@@ -704,8 +717,9 @@
         if (!isFixedRotationTransforming()) {
             return null;
         }
-        return new FixedRotationAdjustments(mFixedRotationTransformState.mDisplayInfo.rotation,
-                mFixedRotationTransformState.mDisplayInfo.displayCutout);
+        final DisplayInfo displayInfo = mFixedRotationTransformState.mDisplayInfo;
+        return new FixedRotationAdjustments(displayInfo.rotation, displayInfo.appWidth,
+                displayInfo.appHeight, displayInfo.displayCutout);
     }
 
     @Override
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 1b649fd..44462c3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -54,6 +54,7 @@
         "com_android_server_UsbDescriptorParser.cpp",
         "com_android_server_UsbMidiDevice.cpp",
         "com_android_server_UsbHostManager.cpp",
+        "com_android_server_VibratorManagerService.cpp",
         "com_android_server_VibratorService.cpp",
         "com_android_server_PersistentDataBlockService.cpp",
         "com_android_server_am_CachedAppOptimizer.cpp",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 8646a53..4c017f5 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -2,6 +2,7 @@
 per-file com_android_server_lights_LightsService.cpp = michaelwr@google.com, santoscordon@google.com
 
 # Haptics
+per-file com_android_server_VibratorManagerService.cpp = michaelwr@google.com
 per-file com_android_server_VibratorService.cpp = michaelwr@google.com
 
 # Input
diff --git a/services/core/jni/com_android_server_VibratorManagerService.cpp b/services/core/jni/com_android_server_VibratorManagerService.cpp
new file mode 100644
index 0000000..dae9cef
--- /dev/null
+++ b/services/core/jni/com_android_server_VibratorManagerService.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VibratorManagerService"
+
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+namespace android {
+
+class NativeVibratorManagerService {
+public:
+    NativeVibratorManagerService() : mHal(std::make_unique<vibrator::LegacyManagerHalWrapper>()) {}
+    ~NativeVibratorManagerService() = default;
+
+    vibrator::ManagerHalWrapper* hal() const { return mHal.get(); }
+
+private:
+    const std::unique_ptr<vibrator::ManagerHalWrapper> mHal;
+};
+
+static void destroyNativeService(void* ptr) {
+    NativeVibratorManagerService* service = reinterpret_cast<NativeVibratorManagerService*>(ptr);
+    if (service) {
+        delete service;
+    }
+}
+
+static jlong nativeInit(JNIEnv* /* env */, jclass /* clazz */) {
+    std::unique_ptr<NativeVibratorManagerService> service =
+            std::make_unique<NativeVibratorManagerService>();
+    return reinterpret_cast<jlong>(service.release());
+}
+
+static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
+}
+
+static jintArray nativeGetVibratorIds(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
+    NativeVibratorManagerService* service =
+            reinterpret_cast<NativeVibratorManagerService*>(servicePtr);
+    if (service == nullptr) {
+        ALOGE("nativeGetVibratorIds failed because native service was not initialized");
+        return nullptr;
+    }
+    auto result = service->hal()->getVibratorIds();
+    if (!result.isOk()) {
+        return nullptr;
+    }
+    std::vector<int32_t> vibratorIds = result.value();
+    jintArray ids = env->NewIntArray(vibratorIds.size());
+    env->SetIntArrayRegion(ids, 0, vibratorIds.size(), reinterpret_cast<jint*>(vibratorIds.data()));
+    return ids;
+}
+
+static const JNINativeMethod method_table[] = {
+        {"nativeInit", "()J", (void*)nativeInit},
+        {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
+        {"nativeGetVibratorIds", "(J)[I", (void*)nativeGetVibratorIds},
+};
+
+int register_android_server_VibratorManagerService(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/server/VibratorManagerService", method_table,
+                                    NELEM(method_table));
+}
+
+}; // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index e7f6db9..48d5244 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -38,6 +38,7 @@
 int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_vr_VrManagerService(JNIEnv* env);
+int register_android_server_VibratorManagerService(JNIEnv* env);
 int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env);
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
@@ -92,6 +93,7 @@
     register_android_server_UsbAlsaJackDetector(env);
     register_android_server_UsbHostManager(env);
     register_android_server_vr_VrManagerService(env);
+    register_android_server_VibratorManagerService(env);
     register_android_server_VibratorService(vm, env);
     register_android_server_SystemServer(env);
     register_android_server_location_GnssLocationProvider(env);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 44a07a1..e8bf468 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -308,6 +308,7 @@
     }
     mJobCondition.notify_all();
     mJobProcessor.join();
+    mLooper->wake();
     mCmdLooperThread.join();
     mTimedQueue->stop();
     mProgressUpdateJobQueue->stop();
@@ -1386,7 +1387,7 @@
 }
 
 void IncrementalService::runCmdLooper() {
-    constexpr auto kTimeoutMsecs = 1000;
+    constexpr auto kTimeoutMsecs = -1;
     while (mRunning.load(std::memory_order_relaxed)) {
         mLooper->pollAll(kTimeoutMsecs);
     }
diff --git a/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java
new file mode 100644
index 0000000..8a22a2f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+
+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;
+
+/**
+ * Tests for {@link VibratorManagerService}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibratorManagerServiceTest
+ */
+@Presubmit
+public class VibratorManagerServiceTest {
+
+    @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+    @Mock private VibratorManagerService.NativeWrapper mNativeWrapperMock;
+
+    @Before
+    public void setUp() throws Exception {
+    }
+
+    private VibratorManagerService createService() {
+        return new VibratorManagerService(InstrumentationRegistry.getContext(),
+                new VibratorManagerService.Injector() {
+                    @Override
+                    VibratorManagerService.NativeWrapper getNativeWrapper() {
+                        return mNativeWrapperMock;
+                    }
+                });
+    }
+
+    @Test
+    public void createService_initializesNativeService() {
+        createService();
+        verify(mNativeWrapperMock).init();
+    }
+
+    @Test
+    public void getVibratorIds_withNullResultFromNative_returnsEmptyArray() {
+        when(mNativeWrapperMock.getVibratorIds()).thenReturn(null);
+        assertArrayEquals(new int[0], createService().getVibratorIds());
+    }
+
+    @Test
+    public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() {
+        when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{ 1, 2 });
+        assertArrayEquals(new int[]{ 1, 2 }, createService().getVibratorIds());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
new file mode 100644
index 0000000..488e5cd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.am;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@RunWith(AndroidJUnit4.class)
+public final class BatteryStatsServiceTest {
+
+    private BatteryStatsService mBatteryStatsService;
+    private HandlerThread mBgThread;
+
+    @Before
+    public void setUp() {
+        final Context context = InstrumentationRegistry.getContext();
+        mBgThread = new HandlerThread("bg thread");
+        mBgThread.start();
+        mBatteryStatsService = new BatteryStatsService(context,
+                context.getCacheDir(), new Handler(mBgThread.getLooper()));
+    }
+
+    @After
+    public void tearDown() {
+        mBatteryStatsService.shutdown();
+        mBgThread.quitSafely();
+    }
+
+    @Test
+    public void testAwaitCompletion() throws Exception {
+        final CountDownLatch readyLatch = new CountDownLatch(2);
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        final CountDownLatch testLatch = new CountDownLatch(1);
+        final AtomicBoolean quiting = new AtomicBoolean(false);
+        final AtomicBoolean finished = new AtomicBoolean(false);
+        final int uid = Process.myUid();
+        final Thread noteThread = new Thread(() -> {
+            final int maxIterations = 1000;
+            final int eventCode = 12345;
+            final String eventName = "placeholder";
+            final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+
+            readyLatch.countDown();
+            try {
+                startLatch.await();
+            } catch (InterruptedException e) {
+            }
+
+            for (int i = 0; i < maxIterations && !quiting.get(); i++) {
+                synchronized (stats) {
+                    mBatteryStatsService.noteEvent(eventCode, eventName, uid);
+                }
+            }
+            finished.set(true);
+        });
+        final Thread waitThread = new Thread(() -> {
+            readyLatch.countDown();
+            try {
+                startLatch.await();
+            } catch (InterruptedException e) {
+            }
+
+            do {
+                mBatteryStatsService.takeUidSnapshot(uid);
+            } while (!finished.get() && !quiting.get());
+
+            if (!quiting.get()) {
+                // do one more to ensure we've cleared the queue
+                mBatteryStatsService.takeUidSnapshot(uid);
+            }
+
+            testLatch.countDown();
+        });
+        noteThread.start();
+        waitThread.start();
+        readyLatch.await();
+        startLatch.countDown();
+
+        try {
+            assertTrue("Timed out in waiting for the completion of battery event handling",
+                    testLatch.await(10 * 1000, TimeUnit.MILLISECONDS));
+        } finally {
+            quiting.set(true);
+            noteThread.interrupt();
+            noteThread.join(1000);
+            waitThread.interrupt();
+            waitThread.join(1000);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index cc1fdab..e011c797 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -123,8 +123,7 @@
 
         final String[] config = {
                 "0:2:15", // ID0:Fingerprint:Strong
-                "1:4:255", // ID1:Iris:Weak
-                "2:8:4095", // ID2:Face:Convenience
+                "1:8:4095", // ID2:Face:Convenience
         };
 
         when(mInjector.getConfiguration(any())).thenReturn(config);
@@ -133,12 +132,14 @@
         mAuthService.onStart();
 
         final int fingerprintId = 0;
-        final int irisId = 1;
-        final int faceId = 2;
+        final int faceId = 1;
 
-        verify(mFingerprintService).initializeConfiguration(eq(fingerprintId));
-        verify(mIrisService).initializeConfiguration(eq(irisId));
-        verify(mFaceService).initializeConfiguration(eq(faceId));
+        final int fingerprintStrength = 15;
+        final int faceStrength = 4095;
+
+        verify(mFingerprintService).initializeConfiguration(eq(fingerprintId),
+                eq(fingerprintStrength));
+        verify(mFaceService).initializeConfiguration(eq(faceId), eq(faceStrength));
     }
 
 
diff --git a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
index 7b88a0e..4f0cb32 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
@@ -32,9 +32,11 @@
     public void setAndGetMatrix() {
         final GlobalSaturationTintController tintController = new GlobalSaturationTintController();
         tintController.setMatrix(50);
-        assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f)
-                .of(new float[]{0.6155f, 0.1155f, 0.1155f, 0.0f, 0.3575f, 0.85749996f, 0.3575f,
-                        0.0f, 0.036f, 0.036f, 0.536f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f});
+        assertThat(tintController.getMatrix()).usingTolerance(0.00001f)
+                .containsExactly(
+                        0.6155f, 0.1155f, 0.1155f, 0.0f, 0.3575f, 0.85749996f, 0.3575f,
+                        0.0f, 0.036f, 0.036f, 0.536f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)
+                .inOrder();
     }
 
     @Test
@@ -43,6 +45,7 @@
         tintController.setMatrix(100);
         final float[] matrix = new float[16];
         Matrix.setIdentityM(matrix, 0);
-        assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f).of(matrix);
+        assertThat(tintController.getMatrix()).usingTolerance(0.00001f)
+                .containsExactly(matrix).inOrder();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index dac0542..bc74783 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -62,6 +62,7 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.PermissionSettings;
 
 import com.google.common.truth.Truth;
@@ -94,6 +95,8 @@
     PermissionSettings mPermissionSettings;
     @Mock
     RuntimePermissionsPersistence mRuntimePermissionsPersistence;
+    @Mock
+    LegacyPermissionDataProvider mPermissionDataProvider;
 
     @Before
     public void initializeMocks() {
@@ -115,7 +118,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
         verifyKeySetMetaData(settings);
     }
@@ -129,7 +132,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
 
         // write out, read back in and verify the same
@@ -145,7 +148,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
         assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
         assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
@@ -167,13 +170,13 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
         settings.writeLPr();
 
         // Create Settings again to make it read from the new files
         settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
 
         PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
@@ -196,7 +199,8 @@
         writePackageRestrictions_noSuspendingPackageXml(0);
         final Object lock = new Object();
         final Context context = InstrumentationRegistry.getTargetContext();
-        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
+                lock);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
         settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -219,7 +223,8 @@
         writePackageRestrictions_noSuspendParamsMapXml(0);
         final Object lock = new Object();
         final Context context = InstrumentationRegistry.getTargetContext();
-        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
+                lock);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
         settingsUnderTest.readPackageRestrictionsLPr(0);
 
@@ -246,7 +251,7 @@
     @Test
     public void testReadWritePackageRestrictions_suspendInfo() {
         final Context context = InstrumentationRegistry.getTargetContext();
-        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
                 new Object());
         final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
         final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
@@ -344,7 +349,7 @@
     @Test
     public void testReadWritePackageRestrictions_distractionFlags() {
         final Context context = InstrumentationRegistry.getTargetContext();
-        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
                 new Object());
         final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
         final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
@@ -389,7 +394,7 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         final Object lock = new Object();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
         ps1.appId = Process.FIRST_APPLICATION_UID;
         ps1.pkg = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
@@ -465,7 +470,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         assertThat(settings.readLPw(createFakeUsers()), is(true));
 
         // Enable/Disable a package
@@ -638,7 +643,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         final SharedUserSetting testUserSetting01 = createSharedUserSetting(
                 testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
         final PackageSetting testPkgSetting01 =
@@ -748,7 +753,7 @@
         final Context context = InstrumentationRegistry.getContext();
         final Object lock = new Object();
         final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
-                mRuntimePermissionsPersistence, lock);
+                mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
         final SharedUserSetting testUserSetting01 = createSharedUserSetting(
                 testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
         final PackageSetting testPkgSetting01 = Settings.createNewSetting(
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index a550b27..f1930d7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -44,7 +44,8 @@
 public class SELinuxMMACTest {
 
     private static final String PACKAGE_NAME = "my.package";
-    private static final int OPT_IN_VERSION = Build.VERSION_CODES.R;
+    private static final int LATEST_OPT_IN_VERSION = Build.VERSION_CODES.S;
+    private static final int R_OPT_IN_VERSION = Build.VERSION_CODES.R;
 
     @Mock
     PlatformCompat mMockCompatibility;
@@ -56,7 +57,17 @@
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(true);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
-                is("default:targetSdkVersion=" + OPT_IN_VERSION));
+                is("default:targetSdkVersion=" + LATEST_OPT_IN_VERSION));
+    }
+
+    @Test
+    public void getSeInfoOptInToR() {
+        AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_R_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(true);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + R_OPT_IN_VERSION));
     }
 
     @Test
@@ -70,13 +81,33 @@
     }
 
     @Test
-    public void getSeInfoNoOptInButAlreadyR() {
-        AndroidPackage pkg = makePackage(OPT_IN_VERSION);
+    public void getSeInfoNoOptInButAlreadyLatest() {
+        AndroidPackage pkg = makePackage(LATEST_OPT_IN_VERSION);
         when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(false);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
-                is("default:targetSdkVersion=" + OPT_IN_VERSION));
+                is("default:targetSdkVersion=" + LATEST_OPT_IN_VERSION));
+    }
+
+    @Test
+    public void getSeInfoNoOptInButAlreadyR() {
+        AndroidPackage pkg = makePackage(R_OPT_IN_VERSION);
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_R_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(false);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + R_OPT_IN_VERSION));
+    }
+
+    @Test
+    public void getSeInfoOptInRButLater() {
+        AndroidPackage pkg = makePackage(R_OPT_IN_VERSION + 1);
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_R_CHANGES),
+                argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
+                .thenReturn(true);
+        assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
+                is("default:targetSdkVersion=" + (R_OPT_IN_VERSION + 1)));
     }
 
     private AndroidPackage makePackage(int targetSdkVersion) {
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index ebcf10d..509eb25 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -59,6 +59,7 @@
 import android.os.HwParcel;
 import android.os.IHwBinder;
 import android.os.IHwInterface;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SharedMemory;
 import android.system.ErrnoException;
@@ -126,7 +127,7 @@
         model.uuid = "12345678-2345-3456-4567-abcdef987654";
         model.vendorUuid = "87654321-5432-6543-7654-456789fedcba";
         byte[] data = new byte[]{91, 92, 93, 94, 95};
-        model.data = byteArrayToFileDescriptor(data);
+        model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data));
         model.dataSize = data.length;
         return model;
     }
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 89a0c7c..f10cab8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -550,7 +550,7 @@
         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         try {
             doReturn(false).when(stack).isTranslucent(any());
-            assertFalse(mStack.shouldBeVisible(null /* starting */));
+            assertTrue(mStack.shouldBeVisible(null /* starting */));
 
             mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
                     mActivity.getConfiguration()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 245ddb9..e478819 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -63,6 +63,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
 
 import android.app.ActivityOptions;
 import android.app.IApplicationThread;
@@ -800,6 +801,7 @@
         final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
         new ActivityBuilder(mAtm).setTask(topTask).build();
 
+        doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger();
         // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
         final ActivityOptions options = ActivityOptions.makeBasic()
                 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
@@ -813,6 +815,9 @@
 
         // Ensure secondary display only creates two stacks.
         verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
+        // The metrics logger should receive the same result and non-null options.
+        verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */,
+                eq(result), eq(singleTaskActivity), notNull() /* options */);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index f4b50dc..54b2b3b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -18,6 +18,8 @@
 
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -39,6 +41,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+/**
+ * Build/Install/Run:
+ *  atest WmTests:DisplayAreaOrganizerTest
+ */
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
@@ -61,14 +67,22 @@
     }
 
     private IDisplayAreaOrganizer registerMockOrganizer(int feature) {
-        final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class);
-        when(organizer.asBinder()).thenReturn(new Binder());
+        return registerMockOrganizer(feature, new Binder());
+    }
 
+    private IDisplayAreaOrganizer registerMockOrganizer(int feature, Binder binder) {
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(binder);
         mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
                 .registerOrganizer(organizer, feature);
         return organizer;
     }
 
+    private IDisplayAreaOrganizer createMockOrganizer(Binder binder) {
+        final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class);
+        when(organizer.asBinder()).thenReturn(binder);
+        return organizer;
+    }
+
     private void unregisterMockOrganizer(IDisplayAreaOrganizer organizer) {
         mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController
                 .unregisterOrganizer(organizer);
@@ -99,4 +113,16 @@
         // Ensure it was still only called once if the bounds didn't change
         verify(organizer).onDisplayAreaInfoChanged(any());
     }
+
+    @Test
+    public void testUnregisterOrganizer() {
+        final Binder binder = new Binder();
+        registerMockOrganizer(FEATURE_VENDOR_FIRST, binder);
+
+        assertThat(mTestDisplayArea.mOrganizer).isNotNull();
+
+        unregisterMockOrganizer(createMockOrganizer(binder));
+
+        assertThat(mTestDisplayArea.mOrganizer).isNull();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 89a34cf..633d216 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1163,6 +1163,8 @@
         mDisplayContent.getDisplayRotation().setRotation(ROTATION_0);
         mDisplayContent.computeScreenConfiguration(config);
         mDisplayContent.onRequestedOverrideConfigurationChanged(config);
+        assertNotEquals(config90.windowConfiguration.getMaxBounds(),
+                config.windowConfiguration.getMaxBounds());
 
         final ActivityRecord app = mAppWindow.mActivityRecord;
         app.setVisible(false);
@@ -1218,8 +1220,9 @@
         verify(t, never()).setPosition(any(), eq(0), eq(0));
 
         // Launch another activity before the transition is finished.
-        final ActivityRecord app2 = new TaskBuilder(mSupervisor)
-                .setDisplay(mDisplayContent).setCreateActivity(true).build().getTopMostActivity();
+        final Task task2 = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
+        final ActivityRecord app2 = new ActivityBuilder(mAtm).setStack(task2)
+                .setUseProcess(app.app).build();
         app2.setVisible(false);
         mDisplayContent.mOpeningApps.add(app2);
         app2.setRequestedOrientation(newOrientation);
@@ -1229,6 +1232,12 @@
         assertTrue(app.hasFixedRotationTransform(app2));
         assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));
 
+        final Configuration expectedProcConfig = new Configuration(app2.app.getConfiguration());
+        expectedProcConfig.windowConfiguration.setActivityType(
+                WindowConfiguration.ACTIVITY_TYPE_UNDEFINED);
+        assertEquals("The process should receive rotated configuration for compatibility",
+                expectedProcConfig, app2.app.getConfiguration());
+
         // The fixed rotation transform can only be finished when all animation finished.
         doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
similarity index 60%
rename from services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
rename to services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index f53894a..c3e1922 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -40,107 +40,107 @@
 
 /**
  * Build/Install/Run:
- * atest WmTests:HighRefreshRateBlacklistTest
+ * atest WmTests:HighRefreshRateDenylistTest
  */
 @SmallTest
 @Presubmit
-public class HighRefreshRateBlacklistTest {
+public class HighRefreshRateDenylistTest {
     private static final String APP1 = "com.android.sample1";
     private static final String APP2 = "com.android.sample2";
     private static final String APP3 = "com.android.sample3";
 
-    private HighRefreshRateBlacklist mBlacklist;
+    private HighRefreshRateDenylist mDenylist;
 
     @After
     public void tearDown() {
-        mBlacklist.dispose();
+        mDenylist.dispose();
     }
 
     @Test
-    public void testDefaultBlacklist() {
+    public void testDefaultDenylist() {
         final Resources r = createResources(APP1, APP2);
-        mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig());
+        mDenylist = new HighRefreshRateDenylist(r, new FakeDeviceConfig());
 
-        assertTrue(mBlacklist.isBlacklisted(APP1));
-        assertTrue(mBlacklist.isBlacklisted(APP2));
-        assertFalse(mBlacklist.isBlacklisted(APP3));
+        assertTrue(mDenylist.isDenylisted(APP1));
+        assertTrue(mDenylist.isDenylisted(APP2));
+        assertFalse(mDenylist.isDenylisted(APP3));
     }
 
     @Test
-    public void testNoDefaultBlacklist() {
+    public void testNoDefaultDenylist() {
         final Resources r = createResources();
-        mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig());
+        mDenylist = new HighRefreshRateDenylist(r, new FakeDeviceConfig());
 
-        assertFalse(mBlacklist.isBlacklisted(APP1));
+        assertFalse(mDenylist.isDenylisted(APP1));
     }
 
     @Test
-    public void testDefaultBlacklistIsOverriddenByDeviceConfig() {
+    public void testDefaultDenylistIsOverriddenByDeviceConfig() {
         final Resources r = createResources(APP1);
         final FakeDeviceConfig config = new FakeDeviceConfig();
-        config.setBlacklist(APP2 + "," + APP3);
-        mBlacklist = new HighRefreshRateBlacklist(r, config);
+        config.setDenylist(APP2 + "," + APP3);
+        mDenylist = new HighRefreshRateDenylist(r, config);
 
-        assertFalse(mBlacklist.isBlacklisted(APP1));
-        assertTrue(mBlacklist.isBlacklisted(APP2));
-        assertTrue(mBlacklist.isBlacklisted(APP3));
+        assertFalse(mDenylist.isDenylisted(APP1));
+        assertTrue(mDenylist.isDenylisted(APP2));
+        assertTrue(mDenylist.isDenylisted(APP3));
     }
 
     @Test
-    public void testDefaultBlacklistIsOverriddenByEmptyDeviceConfig() {
+    public void testDefaultDenylistIsOverriddenByEmptyDeviceConfig() {
         final Resources r = createResources(APP1);
         final FakeDeviceConfig config = new FakeDeviceConfig();
-        config.setBlacklist("");
-        mBlacklist = new HighRefreshRateBlacklist(r, config);
+        config.setDenylist("");
+        mDenylist = new HighRefreshRateDenylist(r, config);
 
-        assertFalse(mBlacklist.isBlacklisted(APP1));
+        assertFalse(mDenylist.isDenylisted(APP1));
     }
 
     @Test
-    public void testDefaultBlacklistIsOverriddenByDeviceConfigUpdate() {
+    public void testDefaultDenylistIsOverriddenByDeviceConfigUpdate() {
         final Resources r = createResources(APP1);
         final FakeDeviceConfig config = new FakeDeviceConfig();
-        mBlacklist = new HighRefreshRateBlacklist(r, config);
+        mDenylist = new HighRefreshRateDenylist(r, config);
 
         // First check that the default denylist is in effect
-        assertTrue(mBlacklist.isBlacklisted(APP1));
-        assertFalse(mBlacklist.isBlacklisted(APP2));
-        assertFalse(mBlacklist.isBlacklisted(APP3));
+        assertTrue(mDenylist.isDenylisted(APP1));
+        assertFalse(mDenylist.isDenylisted(APP2));
+        assertFalse(mDenylist.isDenylisted(APP3));
 
         //  Then confirm that the DeviceConfig list has propagated and taken effect.
-        config.setBlacklist(APP2 + "," + APP3);
-        assertFalse(mBlacklist.isBlacklisted(APP1));
-        assertTrue(mBlacklist.isBlacklisted(APP2));
-        assertTrue(mBlacklist.isBlacklisted(APP3));
+        config.setDenylist(APP2 + "," + APP3);
+        assertFalse(mDenylist.isDenylisted(APP1));
+        assertTrue(mDenylist.isDenylisted(APP2));
+        assertTrue(mDenylist.isDenylisted(APP3));
 
         //  Finally make sure we go back to the default list if the DeviceConfig gets deleted.
-        config.setBlacklist(null);
-        assertTrue(mBlacklist.isBlacklisted(APP1));
-        assertFalse(mBlacklist.isBlacklisted(APP2));
-        assertFalse(mBlacklist.isBlacklisted(APP3));
+        config.setDenylist(null);
+        assertTrue(mDenylist.isDenylisted(APP1));
+        assertFalse(mDenylist.isDenylisted(APP2));
+        assertFalse(mDenylist.isDenylisted(APP3));
     }
 
     @Test
     public void testOverriddenByDeviceConfigUnrelatedFlagChanged() {
         final Resources r = createResources(APP1);
         final FakeDeviceConfig config = new FakeDeviceConfig();
-        mBlacklist = new HighRefreshRateBlacklist(r, config);
-        config.setBlacklist(APP2 + "," + APP3);
-        assertFalse(mBlacklist.isBlacklisted(APP1));
-        assertTrue(mBlacklist.isBlacklisted(APP2));
-        assertTrue(mBlacklist.isBlacklisted(APP3));
+        mDenylist = new HighRefreshRateDenylist(r, config);
+        config.setDenylist(APP2 + "," + APP3);
+        assertFalse(mDenylist.isDenylisted(APP1));
+        assertTrue(mDenylist.isDenylisted(APP2));
+        assertTrue(mDenylist.isDenylisted(APP3));
 
         //  Change an unrelated flag in our namespace and verify that the denylist is intact
         config.putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, "someKey", "someValue");
-        assertFalse(mBlacklist.isBlacklisted(APP1));
-        assertTrue(mBlacklist.isBlacklisted(APP2));
-        assertTrue(mBlacklist.isBlacklisted(APP3));
+        assertFalse(mDenylist.isDenylisted(APP1));
+        assertTrue(mDenylist.isDenylisted(APP2));
+        assertTrue(mDenylist.isDenylisted(APP3));
     }
 
-    private Resources createResources(String... defaultBlacklist) {
+    private Resources createResources(String... defaultDenylist) {
         Resources r = mock(Resources.class);
         when(r.getStringArray(R.array.config_highRefreshRateBlacklist))
-                .thenReturn(defaultBlacklist);
+                .thenReturn(defaultDenylist);
         return r;
     }
 
@@ -160,9 +160,9 @@
             super.addOnPropertiesChangedListener(namespace, executor, listener);
         }
 
-        void setBlacklist(String blacklist) {
+        void setDenylist(String denylist) {
             putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
-                    KEY_HIGH_REFRESH_RATE_BLACKLIST, blacklist);
+                    KEY_HIGH_REFRESH_RATE_BLACKLIST, denylist);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index e887be0..77a4b05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -48,7 +48,7 @@
     private static final int LOW_MODE_ID = 3;
 
     private RefreshRatePolicy mPolicy;
-    private HighRefreshRateBlacklist mBlacklist = mock(HighRefreshRateBlacklist.class);
+    private HighRefreshRateDenylist mDenylist = mock(HighRefreshRateDenylist.class);
 
     @Before
     public void setUp() {
@@ -61,7 +61,7 @@
                         defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 60),
         };
         di.defaultModeId = 1;
-        mPolicy = new RefreshRatePolicy(mWm, di, mBlacklist);
+        mPolicy = new RefreshRatePolicy(mWm, di, mDenylist);
     }
 
     @Test
@@ -81,7 +81,7 @@
         final WindowState blacklistedWindow = createWindow(null, TYPE_BASE_APPLICATION,
                 "blacklistedWindow");
         blacklistedWindow.mAttrs.packageName = "com.android.test";
-        when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+        when(mDenylist.isDenylisted("com.android.test")).thenReturn(true);
         assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(blacklistedWindow));
     }
 
@@ -90,7 +90,7 @@
         final WindowState overrideWindow = createWindow(null, TYPE_BASE_APPLICATION,
                 "overrideWindow");
         overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
-        when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+        when(mDenylist.isDenylisted("com.android.test")).thenReturn(true);
         assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index ef74861..25ba6db3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -68,6 +68,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -142,6 +143,9 @@
         assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
     }
 
+    // Decor windows (i.e windows using PRIVATE_FLAG_IS_SCREEN_DECOR) are no longer supported.
+    // PRIVATE_FLAG_IS_SCREEN_DECOR and related code will be deprecated/removed soon.
+    @Ignore
     @Test
     public void testMultipleDecors() {
         // Test 2 decor windows on-top.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 026396e..6f5389d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -338,7 +338,7 @@
         // HighRefreshRateBlacklist with DeviceConfig. We need to undo that here to avoid
         // leaking mWmService.
         mWmService.mConstants.dispose();
-        mWmService.mHighRefreshRateBlacklist.dispose();
+        mWmService.mHighRefreshRateDenylist.dispose();
 
         // This makes sure the posted messages without delay are processed, e.g.
         // DisplayPolicy#release, WindowManagerService#setAnimationScale.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index e71f7ec..8b025e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -29,6 +29,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -277,6 +279,24 @@
         assertThat(secondTaskDisplayArea.isLastFocused()).isTrue();
     }
 
+    @Test
+    public void testIgnoreOrientationRequest() {
+        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+        final Task stack = taskDisplayArea.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setStack(stack).build();
+
+        mDisplayContent.setFocusedApp(activity);
+        activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+
+        taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
+    }
+
     private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask,
             boolean reuseCandidate) {
         final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 11eaf8c..0152fc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -26,6 +26,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -42,6 +45,8 @@
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -361,6 +366,45 @@
     }
 
     @Test
+    public void testSetIgnoreOrientationRequest() {
+        removeGlobalMinSizeRestriction();
+        final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+        final Task stack = taskDisplayArea.createStack(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+        final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+                .setStack(stack).build();
+        taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplayContent.setFocusedApp(activity);
+        activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        // TDA returns UNSET when ignoreOrientationRequest == true
+        // DC is UNSPECIFIED because it is using the previous (default) when TDA returns UNSET.
+        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
+        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
+
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        t.setIgnoreOrientationRequest(
+                taskDisplayArea.mRemoteToken.toWindowContainerToken(),
+                false /* ignoreOrientationRequest */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+
+        // TDA returns app request orientation when ignoreOrientationRequest == false
+        // DC uses the same as TDA returns when it is not UNSET.
+        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+
+        t.setIgnoreOrientationRequest(
+                taskDisplayArea.mRemoteToken.toWindowContainerToken(),
+                true /* ignoreOrientationRequest */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+
+        // TDA returns UNSET when ignoreOrientationRequest == true
+        // DC is LANDSCAPE because it is using the previous when TDA returns UNSET.
+        assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
+        assertThat(mDisplayContent.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+    }
+
+    @Test
     public void testOverrideConfigSize() {
         removeGlobalMinSizeRestriction();
         final Task stack = new TaskBuilder(mSupervisor)
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 189e540..38c7531 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -266,6 +266,15 @@
         mWpc.onMergedOverrideConfigurationChanged(config);
         assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType());
         assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType());
+
+        final int globalSeq = 100;
+        mRootWindowContainer.getConfiguration().seq = globalSeq;
+        invertOrientation(mWpc.getConfiguration());
+        new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(mWpc).build();
+
+        assertTrue(mWpc.registeredForActivityConfigChanges());
+        assertEquals("Config seq of process should not be affected by activity",
+                mWpc.getConfiguration().seq, globalSeq);
     }
 
     private TestDisplayContent createTestDisplayContentInContainer() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0ec2793..a82d988 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1888,8 +1888,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -1941,8 +1941,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -2010,8 +2010,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -2088,8 +2088,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -2126,8 +2126,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -2210,8 +2210,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -2247,8 +2247,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -3723,8 +3723,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -3761,8 +3761,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -4015,8 +4015,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
@@ -4054,8 +4054,8 @@
      *
      * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
      * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of
-     * the following requirements is met:
+     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
+     * method can be invoked if one of the following requirements is met:
      * <ul>
      *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
      *     is a privileged permission that can only be granted to apps preloaded on the device.
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
index 026677e..99dde85 100644
--- a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
@@ -62,13 +63,62 @@
             CLog.w("Iteration N" + iteration);
             final int userId = createManagedProfile();
             startUser(userId);
-            installPackageAsUser(DUMMY_DPC_APK, true /* grantPermissions */, userId, "-t");
+            installPackageAsUser(
+                    DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
             setProfileOwner(DUMMY_DPC_COMPONENT, userId);
             removeUser(userId);
         }
         CLog.w("Completed " + iteration + " iterations.");
     }
 
+    /**
+     * Create, start, and kill managed profiles in a loop with waitForBroadcastIdle after each user
+     * operation.
+     */
+    @Test
+    public void testCreateStartDeleteStable() throws Exception {
+        // Disable package verifier for ADB installs.
+        getDevice().executeShellCommand("settings put global verifier_verify_adb_installs 0");
+        int iteration = 0;
+        final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
+        while (System.nanoTime() < deadline) {
+            iteration++;
+            CLog.w("Iteration N" + iteration);
+            final int userId = createManagedProfile();
+            waitForBroadcastIdle();
+
+            startUser(userId);
+            waitForBroadcastIdle();
+
+            installPackageAsUser(
+                    DUMMY_DPC_APK, /* grantPermissions= */true, userId, /* options= */"-t");
+
+            setProfileOwner(DUMMY_DPC_COMPONENT, userId);
+
+            removeUser(userId);
+            waitForBroadcastIdle();
+        }
+        CLog.w("Completed " + iteration + " iterations.");
+    }
+
+    private void waitForBroadcastIdle() throws Exception {
+        final CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+        // We allow 8min for the command to complete and 4min for the command to start to
+        // output something.
+        getDevice().executeShellCommand(
+                "am wait-for-broadcast-idle",
+                receiver,
+                /* maxTimeoutForCommand= */8,
+                /* maxTimeoutToOutputShellResponse= */4,
+                TimeUnit.MINUTES,
+                /* retryAttempts= */0);
+        final String output = receiver.getOutput();
+        if (!output.contains("All broadcast queues are idle!")) {
+            CLog.e("Output from 'am wait-for-broadcast-idle': %s", output);
+            fail("'am wait-for-broadcase-idle' did not complete.");
+        }
+    }
+
     private int createManagedProfile() throws Exception {
         final String output = getDevice().executeShellCommand(
                 "pm create-user --profileOf 0 --managed TestProfile");
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 9f0b41f..c895420 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -67,6 +67,9 @@
     private NetworkAgent mNetworkAgent;
     private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
     private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+    // Controls how test network agent is going to wait before responding to keepalive
+    // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
+    private long mKeepaliveResponseDelay = 0L;
     private Integer mExpectedKeepaliveSlot = null;
 
     public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
@@ -134,12 +137,17 @@
             if (mWrapper.mExpectedKeepaliveSlot != null) {
                 assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
             }
-            onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+            mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+                    () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
+                    mWrapper.mKeepaliveResponseDelay);
         }
 
         @Override
         public void stopSocketKeepalive(Message msg) {
-            onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+            final int slot = msg.arg1;
+            mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+                    () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
+                    mWrapper.mKeepaliveResponseDelay);
         }
 
         @Override
@@ -248,6 +256,10 @@
         mStopKeepaliveError = reason;
     }
 
+    public void setKeepaliveResponseDelay(long delay) {
+        mKeepaliveResponseDelay = delay;
+    }
+
     public void setExpectedKeepaliveSlot(Integer slot) {
         mExpectedKeepaliveSlot = slot;
     }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1f23bf3..7dfac9c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4292,6 +4292,32 @@
         myNet = connectKeepaliveNetwork(lp);
         mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
 
+        // Check that a stop followed by network disconnects does not result in crash.
+        try (SocketKeepalive ka = mCm.createSocketKeepalive(
+                myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
+            ka.start(validKaInterval);
+            callback.expectStarted();
+            // Delay the response of keepalive events in networkAgent long enough to make sure
+            // the follow-up network disconnection will be processed first.
+            mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
+            ka.stop();
+
+            // Make sure the stop has been processed. Wait for executor idle is needed to prevent
+            // flaky since the actual stop call to the service is delegated to executor thread.
+            waitForIdleSerialExecutor(executor, TIMEOUT_MS);
+            waitForIdle();
+
+            mWiFiNetworkAgent.disconnect();
+            mWiFiNetworkAgent.expectDisconnected();
+            callback.expectStopped();
+            callback.assertNoCallback();
+        }
+
+        // Reconnect.
+        waitForIdle();
+        myNet = connectKeepaliveNetwork(lp);
+        mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
         int srcPort2 = 0;
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 7c150f9..0af6266 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -115,13 +115,13 @@
     }
 
     case FILETYPE_INPUTDEVICECONFIGURATION: {
-        PropertyMap* map;
-        status_t status = PropertyMap::load(String8(filename), &map);
-        if (status) {
-            error("Error %d parsing input device configuration file.\n\n", status);
+        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());
             return false;
         }
-        delete map;
         break;
     }
 
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 3f5c673..1c297e7 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -798,9 +798,15 @@
     method public int describeContents();
     method public String getFqdn();
     method public String getFriendlyName();
+    method @Nullable public long[] getMatchAllOis();
+    method @Nullable public long[] getMatchAnyOis();
+    method @Nullable public String[] getOtherHomePartners();
     method public long[] getRoamingConsortiumOis();
     method public void setFqdn(String);
     method public void setFriendlyName(String);
+    method public void setMatchAllOis(@Nullable long[]);
+    method public void setMatchAnyOis(@Nullable long[]);
+    method public void setOtherHomePartners(@Nullable String[]);
     method public void setRoamingConsortiumOis(long[]);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index aab4a2d..fd45ebe 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -508,7 +508,7 @@
     field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
     field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
     field public static final String EXTRA_CHANGE_REASON = "changeReason";
-    field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+    field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
     field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
     field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c76f4a6..2219bfc 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1053,9 +1053,6 @@
 
     /**
      * Broadcast intent action indicating that the link configuration changed on wifi.
-     * <br />Included Extras:
-     * <br />{@link #EXTRA_LINK_PROPERTIES}: {@link android.net.LinkProperties} object associated
-     * with the Wi-Fi network.
      * <br /> No permissions are required to listen to this broadcast.
      * @hide
      */
@@ -1071,8 +1068,12 @@
      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
      *
      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
+     *
+     * @deprecated this extra is no longer populated.
+     *
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
 
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 8f34579..35a8ff6 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.hotspot2.pps;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -139,16 +140,26 @@
      * (MO) tree for more detail.
      */
     private long[] mMatchAllOis = null;
+
     /**
-     * @hide
+     * Set a list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+     * Consortium advertised by a hotspot operator. The list set by this API will have precedence
+     * over {@link #setMatchAnyOis(long[])}, meaning the list set in {@link #setMatchAnyOis(long[])}
+     * will only be used for matching if the list set by this API is null or empty.
+     *
+     * @param matchAllOis An array of longs containing the HomeOIs
      */
-    public void setMatchAllOis(long[] matchAllOis) {
+    public void setMatchAllOis(@Nullable long[] matchAllOis) {
         mMatchAllOis = matchAllOis;
     }
+
     /**
-     * @hide
+     * Get the list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+     * Consortium advertised by a hotspot operator.
+     *
+     * @return An array of longs containing the HomeOIs
      */
-    public long[] getMatchAllOis() {
+    public @Nullable long[] getMatchAllOis() {
         return mMatchAllOis;
     }
 
@@ -159,23 +170,34 @@
      * of that Hotspot provider (e.g. successful authentication with such Hotspot
      * is possible).
      *
-     * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
-     * only be used for matching if {@link #mMatchAllOIs} is null or empty.
+     * The list set by {@link #setMatchAllOis(long[])} will have precedence over this one, meaning
+     * this list will only be used for matching if the list set by {@link #setMatchAllOis(long[])}
+     * is null or empty.
      *
      * Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
      * (MO) tree for more detail.
      */
     private long[] mMatchAnyOis = null;
+
     /**
-     * @hide
+     * Set a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+     * advertised by a hotspot operator. The list set by {@link #setMatchAllOis(long[])}
+     * will have precedence over this API, meaning this list will only be used for matching if the
+     * list set by {@link #setMatchAllOis(long[])} is null or empty.
+     *
+     * @param matchAnyOis An array of longs containing the HomeOIs
      */
-    public void setMatchAnyOis(long[] matchAnyOis) {
+    public void setMatchAnyOis(@Nullable long[] matchAnyOis) {
         mMatchAnyOis = matchAnyOis;
     }
+
     /**
-     * @hide
+     * Get a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+     * advertised by a hotspot operator.
+     *
+     * @return An array of longs containing the HomeOIs
      */
-    public long[] getMatchAnyOis() {
+    public @Nullable long[] getMatchAnyOis() {
         return mMatchAnyOis;
     }
 
@@ -186,16 +208,25 @@
      * operator merges between the providers.
      */
     private String[] mOtherHomePartners = null;
+
     /**
-     * @hide
+     * Set the list of FQDN (Fully Qualified Domain Name) of other Home partner providers.
+     *
+     * @param otherHomePartners Array of Strings containing the FQDNs of other Home partner
+     *                         providers
      */
-    public void setOtherHomePartners(String[] otherHomePartners) {
+    public void setOtherHomePartners(@Nullable String[] otherHomePartners) {
         mOtherHomePartners = otherHomePartners;
     }
+
     /**
-     * @hide
+     * Get the list of FQDN (Fully Qualified Domain Name) of other Home partner providers set in
+     * the profile.
+     *
+     * @return Array of Strings containing the FQDNs of other Home partner providers set in the
+     * profile
      */
-    public String[] getOtherHomePartners() {
+    public @Nullable String[] getOtherHomePartners() {
         return mOtherHomePartners;
     }