Merge "Expand visibility of projection state API so Android Auto can access it."
diff --git a/Android.bp b/Android.bp
index bc39882..bbaeea5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1300,7 +1300,8 @@
 // into wifi-service
 java_library {
     name: "framework-wifi-util-lib",
-    sdk_version: "module_30",
+    sdk_version: "module_current",
+    min_sdk_version: "30",
     srcs: [
         "core/java/android/content/pm/BaseParceledListSlice.java",
         "core/java/android/content/pm/ParceledListSlice.java",
diff --git a/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
index d78c8b4..0efe8cf 100644
--- a/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
@@ -19,9 +19,9 @@
 import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.content.Context;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
 
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
 
@@ -32,7 +32,7 @@
 @LargeTest
 public class VibratorPerfTest {
     @Rule
-    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+    public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
 
     private Vibrator mVibrator;
 
@@ -44,7 +44,7 @@
 
     @Test
     public void testEffectClick() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
             mVibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
         }
@@ -52,7 +52,7 @@
 
     @Test
     public void testOneShot() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
             mVibrator.vibrate(VibrationEffect.createOneShot(SECONDS.toMillis(2),
                     VibrationEffect.DEFAULT_AMPLITUDE));
@@ -61,7 +61,7 @@
 
     @Test
     public void testWaveform() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         long[] timings = new long[]{SECONDS.toMillis(1), SECONDS.toMillis(2), SECONDS.toMillis(1)};
         while (state.keepRunning()) {
             mVibrator.vibrate(VibrationEffect.createWaveform(timings, -1));
@@ -70,7 +70,7 @@
 
     @Test
     public void testCompose() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         while (state.keepRunning()) {
             mVibrator.vibrate(
                     VibrationEffect.startComposition()
@@ -82,7 +82,7 @@
 
     @Test
     public void testAreEffectsSupported() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
         while (state.keepRunning()) {
             mVibrator.areEffectsSupported(effects);
@@ -91,7 +91,7 @@
 
     @Test
     public void testArePrimitivesSupported() {
-        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final BenchmarkState state = mBenchmarkRule.getState();
         int[] primitives = new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK,
                 VibrationEffect.Composition.PRIMITIVE_TICK};
         while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
new file mode 100644
index 0000000..2a538b2
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class CharsetUtilsPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Parameterized.Parameter(0)
+    public String mName;
+    @Parameterized.Parameter(1)
+    public String mValue;
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Object[]> getParameters() {
+        return Arrays.asList(new Object[][] {
+                { "simple", "com.example.typical_package_name" },
+                { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" },
+        });
+    }
+
+    @Test
+    public void timeUpstream() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            mValue.getBytes(StandardCharsets.UTF_8);
+        }
+    }
+
+    /**
+     * Measure performance of writing into a small buffer where bounds checking
+     * requires careful measurement of encoded size.
+     */
+    @Test
+    public void timeLocal_SmallBuffer() {
+        final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 64);
+        final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            CharsetUtils.toUtf8Bytes(mValue, destPtr, 0, dest.length);
+        }
+    }
+
+    /**
+     * Measure performance of writing into a large buffer where bounds checking
+     * only needs a simple worst-case 4-bytes-per-char check.
+     */
+    @Test
+    public void timeLocal_LargeBuffer() {
+        final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 1024);
+        final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            CharsetUtils.toUtf8Bytes(mValue, destPtr, 0, dest.length);
+       }
+    }
+}
diff --git a/apct-tests/perftests/core/src/android/util/XmlPerfTest.java b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
new file mode 100644
index 0000000..e05bd2a
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
@@ -0,0 +1,292 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Bundle;
+import android.os.Debug;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class XmlPerfTest {
+    /**
+     * Since allocation measurement adds overhead, it's disabled by default for
+     * performance runs. It can be manually enabled to compare GC behavior.
+     */
+    private static final boolean MEASURE_ALLOC = false;
+
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void timeWrite_Fast() throws Exception {
+        doWrite(() -> Xml.newFastSerializer());
+    }
+
+    @Test
+    public void timeWrite_Binary() throws Exception {
+        doWrite(() -> Xml.newBinarySerializer());
+    }
+
+    private void doWrite(Supplier<TypedXmlSerializer> outFactory) throws Exception {
+        if (MEASURE_ALLOC) {
+            Debug.startAllocCounting();
+        }
+
+        int iterations = 0;
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            iterations++;
+            try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                final TypedXmlSerializer out = outFactory.get();
+                out.setOutput(os, StandardCharsets.UTF_8.name());
+                write(out);
+            }
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.stopAllocCounting();
+            final Bundle results = new Bundle();
+            results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+            results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        }
+    }
+
+    @Test
+    public void timeRead_Fast() throws Exception {
+        doRead(() -> Xml.newFastSerializer(), () -> Xml.newFastPullParser());
+    }
+
+    @Test
+    public void timeRead_Binary() throws Exception {
+        doRead(() -> Xml.newBinarySerializer(), () -> Xml.newBinaryPullParser());
+    }
+
+    private void doRead(Supplier<TypedXmlSerializer> outFactory,
+            Supplier<TypedXmlPullParser> inFactory) throws Exception {
+        final byte[] raw;
+        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            TypedXmlSerializer out = outFactory.get();
+            out.setOutput(os, StandardCharsets.UTF_8.name());
+            write(out);
+            raw = os.toByteArray();
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.startAllocCounting();
+        }
+
+        int iterations = 0;
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            iterations++;
+            try (ByteArrayInputStream is = new ByteArrayInputStream(raw)) {
+                TypedXmlPullParser xml = inFactory.get();
+                xml.setInput(is, StandardCharsets.UTF_8.name());
+                read(xml);
+            }
+        }
+
+        if (MEASURE_ALLOC) {
+            Debug.stopAllocCounting();
+            final Bundle results = new Bundle();
+            results.putLong("sizeBytes", raw.length);
+            results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+            results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        } else {
+            final Bundle results = new Bundle();
+            results.putLong("sizeBytes", raw.length);
+            InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+        }
+    }
+
+    /**
+     * Not even joking, this is a typical public key blob stored in
+     * {@code packages.xml}.
+     */
+    private static final byte[] KEY_BLOB = HexDump.hexStringToByteArray(""
+            + "308204a830820390a003020102020900a1573d0f45bea193300d06092a864886f70d010105050030819"
+            + "4310b3009060355040613025553311330110603550408130a43616c69666f726e696131163014060355"
+            + "0407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e06035"
+            + "5040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d"
+            + "0109011613616e64726f696440616e64726f69642e636f6d301e170d3131303931393138343232355a1"
+            + "70d3339303230343138343232355a308194310b3009060355040613025553311330110603550408130a"
+            + "43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e0603550"
+            + "40a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e"
+            + "64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d3"
+            + "0820120300d06092a864886f70d01010105000382010d00308201080282010100de1b51336afc909d8b"
+            + "cca5920fcdc8940578ec5c253898930e985481cfdea75ba6fc54b1f7bb492a03d98db471ab4200103a8"
+            + "314e60ee25fef6c8b83bc1b2b45b084874cffef148fa2001bb25c672b6beba50b7ac026b546da762ea2"
+            + "23829a22b80ef286131f059d2c9b4ca71d54e515a8a3fd6bf5f12a2493dfc2619b337b032a7cf8bbd34"
+            + "b833f2b93aeab3d325549a93272093943bb59dfc0197ae4861ff514e019b73f5cf10023ad1a032adb4b"
+            + "9bbaeb4debecb4941d6a02381f1165e1ac884c1fca9525c5854dce2ad8ec839b8ce78442c16367efc07"
+            + "778a337d3ca2cdf9792ac722b95d67c345f1c00976ec372f02bfcbef0262cc512a6845e71cfea0d0201"
+            + "03a381fc3081f9301d0603551d0e0416041478a0fc4517fb70ff52210df33c8d32290a44b2bb3081c90"
+            + "603551d230481c13081be801478a0fc4517fb70ff52210df33c8d32290a44b2bba1819aa48197308194"
+            + "310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550"
+            + "407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355"
+            + "040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0"
+            + "109011613616e64726f696440616e64726f69642e636f6d820900a1573d0f45bea193300c0603551d13"
+            + "040530030101ff300d06092a864886f70d01010505000382010100977302dfbf668d7c61841c9c78d25"
+            + "63bcda1b199e95e6275a799939981416909722713531157f3cdcfea94eea7bb79ca3ca972bd8058a36a"
+            + "d1919291df42d7190678d4ea47a4b9552c9dfb260e6d0d9129b44615cd641c1080580e8a990dd768c6a"
+            + "b500c3b964e185874e4105109d94c5bd8c405deb3cf0f7960a563bfab58169a956372167a7e2674a04c"
+            + "4f80015d8f7869a7a4139aecbbdca2abc294144ee01e4109f0e47a518363cf6e9bf41f7560e94bdd4a5"
+            + "d085234796b05c7a1389adfd489feec2a107955129d7991daa49afb3d327dc0dc4fe959789372b093a8"
+            + "9c8dbfa41554f771c18015a6cb242a17e04d19d55d3b4664eae12caf2a11cd2b836e");
+
+    /**
+     * Typical list of permissions referenced in {@code packages.xml}.
+     */
+    private static final String[] PERMS = new String[] {
+            "android.permission.ACCESS_CACHE_FILESYSTEM",
+            "android.permission.WRITE_SETTINGS",
+            "android.permission.MANAGE_EXTERNAL_STORAGE",
+            "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS",
+            "android.permission.FOREGROUND_SERVICE",
+            "android.permission.RECEIVE_BOOT_COMPLETED",
+            "android.permission.WRITE_MEDIA_STORAGE",
+            "android.permission.INTERNET",
+            "android.permission.UPDATE_DEVICE_STATS",
+            "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY",
+            "android.permission.MANAGE_USB",
+            "android.permission.ACCESS_ALL_DOWNLOADS",
+            "android.permission.ACCESS_DOWNLOAD_MANAGER",
+            "android.permission.MANAGE_USERS",
+            "android.permission.ACCESS_NETWORK_STATE",
+            "android.permission.ACCESS_MTP",
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS",
+            "android.permission.CLEAR_APP_CACHE",
+            "android.permission.CONNECTIVITY_INTERNAL",
+            "android.permission.START_ACTIVITIES_FROM_BACKGROUND",
+            "android.permission.QUERY_ALL_PACKAGES",
+            "android.permission.WAKE_LOCK",
+            "android.permission.UPDATE_APP_OPS_STATS",
+    };
+
+    /**
+     * Write a typical {@code packages.xml} file containing 100 applications,
+     * each of which defines signing key and permission information.
+     */
+    private static void write(TypedXmlSerializer out) throws IOException {
+        out.startDocument(null, true);
+        out.startTag(null, "packages");
+        for (int i = 0; i < 100; i++) {
+            out.startTag(null, "package");
+            out.attribute(null, "name", "com.android.providers.media");
+            out.attribute(null, "codePath", "/system/priv-app/MediaProviderLegacy");
+            out.attribute(null, "nativeLibraryPath", "/system/priv-app/MediaProviderLegacy/lib");
+            out.attributeLong(null, "publicFlags", 944258629L);
+            out.attributeLong(null, "privateFlags", -1946152952L);
+            out.attributeLong(null, "ft", 1603899064000L);
+            out.attributeLong(null, "it", 1603899064000L);
+            out.attributeLong(null, "ut", 1603899064000L);
+            out.attributeInt(null, "version", 1024);
+            out.attributeInt(null, "sharedUserId", 10100);
+            out.attributeBoolean(null, "isOrphaned", true);
+
+            out.startTag(null, "sigs");
+            out.startTag(null, "cert");
+            out.attributeInt(null, "index", 10);
+            out.attributeBytesHex(null, "key", KEY_BLOB);
+            out.endTag(null, "cert");
+            out.endTag(null, "sigs");
+
+            out.startTag(null, "perms");
+            for (String perm : PERMS) {
+                out.startTag(null, "item");
+                out.attributeInterned(null, "name", perm);
+                out.attributeBoolean(null, "granted", true);
+                out.attributeInt(null, "flags", 0);
+                out.endTag(null, "item");
+            }
+            out.endTag(null, "perms");
+
+            out.endTag(null, "package");
+        }
+        out.endTag(null, "packages");
+        out.endDocument();
+    }
+
+    /**
+     * Read a typical {@code packages.xml} file containing 100 applications, and
+     * verify that data passes smell test.
+     */
+    private static void read(TypedXmlPullParser xml) throws Exception {
+        int type;
+        int packages = 0;
+        int certs = 0;
+        int perms = 0;
+        while ((type = xml.next()) != XmlPullParser.END_DOCUMENT) {
+            final String tag = xml.getName();
+            if (type == XmlPullParser.START_TAG) {
+                if ("package".equals(tag)) {
+                    xml.getAttributeValue(null, "name");
+                    xml.getAttributeValue(null, "codePath");
+                    xml.getAttributeValue(null, "nativeLibraryPath");
+                    xml.getAttributeLong(null, "publicFlags");
+                    assertEquals(-1946152952L, xml.getAttributeLong(null, "privateFlags"));
+                    xml.getAttributeLong(null, "ft");
+                    xml.getAttributeLong(null, "it");
+                    xml.getAttributeLong(null, "ut");
+                    xml.getAttributeInt(null, "version");
+                    xml.getAttributeInt(null, "sharedUserId");
+                    xml.getAttributeBoolean(null, "isOrphaned");
+                    packages++;
+                } else if ("cert".equals(tag)) {
+                    xml.getAttributeInt(null, "index");
+                    xml.getAttributeBytesHex(null, "key");
+                    certs++;
+                } else if ("item".equals(tag)) {
+                    xml.getAttributeValue(null, "name");
+                    xml.getAttributeBoolean(null, "granted");
+                    xml.getAttributeInt(null, "flags");
+                    perms++;
+                }
+            } else if (type == XmlPullParser.TEXT) {
+                xml.getText();
+            }
+        }
+
+        assertEquals(100, packages);
+        assertEquals(packages * 1, certs);
+        assertEquals(packages * PERMS.length, perms);
+    }
+}
diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
new file mode 100644
index 0000000..2700fff
--- /dev/null
+++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.internal.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class FastDataPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    private static final int OUTPUT_SIZE = 64000;
+    private static final int BUFFER_SIZE = 4096;
+
+    @Test
+    public void timeWrite_Upstream() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            os.reset();
+            final BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
+            final DataOutput out = new DataOutputStream(bos);
+            doWrite(out);
+            bos.flush();
+        }
+    }
+
+    @Test
+    public void timeWrite_Local() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            os.reset();
+            final FastDataOutput out = new FastDataOutput(os, BUFFER_SIZE);
+            doWrite(out);
+            out.flush();
+        }
+    }
+
+    @Test
+    public void timeRead_Upstream() throws Exception {
+        final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            is.reset();
+            final BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
+            final DataInput in = new DataInputStream(bis);
+            doRead(in);
+        }
+    }
+
+    @Test
+    public void timeRead_Local() throws Exception {
+        final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            is.reset();
+            final DataInput in = new FastDataInput(is, BUFFER_SIZE);
+            doRead(in);
+        }
+    }
+
+    /**
+     * Since each iteration is around 64 bytes, we need to iterate many times to
+     * exercise the buffer logic.
+     */
+    private static final int REPEATS = 1000;
+
+    private static byte[] doWrite() throws IOException {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+        final DataOutput out = new DataOutputStream(os);
+        doWrite(out);
+        return os.toByteArray();
+    }
+
+    private static void doWrite(DataOutput out) throws IOException {
+        for (int i = 0; i < REPEATS; i++) {
+            out.writeByte(Byte.MAX_VALUE);
+            out.writeShort(Short.MAX_VALUE);
+            out.writeInt(Integer.MAX_VALUE);
+            out.writeLong(Long.MAX_VALUE);
+            out.writeFloat(Float.MAX_VALUE);
+            out.writeDouble(Double.MAX_VALUE);
+            out.writeUTF("com.example.typical_package_name");
+        }
+    }
+
+    private static void doRead(DataInput in) throws IOException {
+        for (int i = 0; i < REPEATS; i++) {
+            in.readByte();
+            in.readShort();
+            in.readInt();
+            in.readLong();
+            in.readFloat();
+            in.readDouble();
+            in.readUTF();
+        }
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 81f22fe..9835e18 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -27,6 +27,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -76,6 +77,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
@@ -273,6 +275,7 @@
     private ActivityManagerInternal mLocalActivityManager;
     private ActivityTaskManagerInternal mLocalActivityTaskManager;
     private DeviceIdleInternal mLocalService;
+    private PackageManagerInternal mPackageManagerInternal;
     private PowerManagerInternal mLocalPowerManager;
     private PowerManager mPowerManager;
     private INetworkPolicyManager mNetworkPolicyManager;
@@ -1736,27 +1739,33 @@
         }
 
         public String[] getRemovedSystemPowerWhitelistApps() {
-            return getRemovedSystemPowerWhitelistAppsInternal();
+            return getRemovedSystemPowerWhitelistAppsInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public String[] getSystemPowerWhitelistExceptIdle() {
-            return getSystemPowerWhitelistExceptIdleInternal();
+            return getSystemPowerWhitelistExceptIdleInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public String[] getSystemPowerWhitelist() {
-            return getSystemPowerWhitelistInternal();
+            return getSystemPowerWhitelistInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public String[] getUserPowerWhitelist() {
-            return getUserPowerWhitelistInternal();
+            return getUserPowerWhitelistInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public String[] getFullPowerWhitelistExceptIdle() {
-            return getFullPowerWhitelistExceptIdleInternal();
+            return getFullPowerWhitelistExceptIdleInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public String[] getFullPowerWhitelist() {
-            return getFullPowerWhitelistInternal();
+            return getFullPowerWhitelistInternal(
+                    Binder.getCallingUid(), UserHandle.getCallingUserId());
         }
 
         @Override public int[] getAppIdWhitelistExceptIdle() {
@@ -1776,10 +1785,18 @@
         }
 
         @Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) {
+            if (mPackageManagerInternal
+                    .filterAppAccess(name, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+                return false;
+            }
             return isPowerSaveWhitelistExceptIdleAppInternal(name);
         }
 
         @Override public boolean isPowerSaveWhitelistApp(String name) {
+            if (mPackageManagerInternal
+                    .filterAppAccess(name, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+                return false;
+            }
             return isPowerSaveWhitelistAppInternal(name);
         }
 
@@ -2159,6 +2176,7 @@
                 mBatteryStats = BatteryStatsService.getService();
                 mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
                 mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
+                mPackageManagerInternal = getLocalService(PackageManagerInternal.class);
                 mLocalPowerManager = getLocalService(PowerManagerInternal.class);
                 mPowerManager = mInjector.getPowerManager();
                 mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -2466,54 +2484,68 @@
         }
     }
 
-    public String[] getSystemPowerWhitelistExceptIdleInternal() {
+    private String[] getSystemPowerWhitelistExceptIdleInternal(final int callingUid,
+            final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
             int size = mPowerSaveWhitelistAppsExceptIdle.size();
-            String[] apps = new String[size];
+            apps = new String[size];
             for (int i = 0; i < size; i++) {
                 apps[i] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
-    public String[] getSystemPowerWhitelistInternal() {
+    private String[] getSystemPowerWhitelistInternal(final int callingUid,
+            final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
             int size = mPowerSaveWhitelistApps.size();
-            String[] apps = new String[size];
+            apps = new String[size];
             for (int i = 0; i < size; i++) {
                 apps[i] = mPowerSaveWhitelistApps.keyAt(i);
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
-    public String[] getRemovedSystemPowerWhitelistAppsInternal() {
+    private String[] getRemovedSystemPowerWhitelistAppsInternal(final int callingUid,
+            final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
             int size = mRemovedFromSystemWhitelistApps.size();
-            final String[] apps = new String[size];
+            apps = new String[size];
             for (int i = 0; i < size; i++) {
                 apps[i] = mRemovedFromSystemWhitelistApps.keyAt(i);
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
-    public String[] getUserPowerWhitelistInternal() {
+    private String[] getUserPowerWhitelistInternal(final int callingUid, final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
             int size = mPowerSaveWhitelistUserApps.size();
-            String[] apps = new String[size];
+            apps = new String[size];
             for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
                 apps[i] = mPowerSaveWhitelistUserApps.keyAt(i);
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
-    public String[] getFullPowerWhitelistExceptIdleInternal() {
+    private String[] getFullPowerWhitelistExceptIdleInternal(final int callingUid,
+            final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
-            int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
-            String[] apps = new String[size];
+            int size =
+                    mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
+            apps = new String[size];
             int cur = 0;
             for (int i = 0; i < mPowerSaveWhitelistAppsExceptIdle.size(); i++) {
                 apps[cur] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
@@ -2523,14 +2555,16 @@
                 apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
                 cur++;
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
-    public String[] getFullPowerWhitelistInternal() {
+    private String[] getFullPowerWhitelistInternal(final int callingUid, final int callingUserId) {
+        final String[] apps;
         synchronized (this) {
             int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
-            String[] apps = new String[size];
+            apps = new String[size];
             int cur = 0;
             for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
                 apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
@@ -2540,8 +2574,9 @@
                 apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
                 cur++;
             }
-            return apps;
         }
+        return ArrayUtils.filter(apps, String[]::new,
+                (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
     }
 
     public boolean isPowerSaveWhitelistExceptIdleAppInternal(String packageName) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 34e82b0..ca002ec 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3139,7 +3139,9 @@
     }
 
     void resetExecutionQuota(@NonNull String pkgName, int userId) {
-        mQuotaController.clearAppStats(userId, pkgName);
+        synchronized (mLock) {
+            mQuotaController.clearAppStatsLocked(userId, pkgName);
+        }
     }
 
     void resetScheduleQuota() {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b7ace70..7d7de3b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -576,7 +576,7 @@
             Slog.wtf(TAG, "Told app removed but given null package name.");
             return;
         }
-        clearAppStats(UserHandle.getUserId(uid), packageName);
+        clearAppStatsLocked(UserHandle.getUserId(uid), packageName);
         mForegroundUids.delete(uid);
         mUidToPackageCache.remove(uid);
     }
@@ -592,7 +592,7 @@
     }
 
     /** Drop all historical stats and stop tracking any active sessions for the specified app. */
-    public void clearAppStats(int userId, @NonNull String packageName) {
+    public void clearAppStatsLocked(int userId, @NonNull String packageName) {
         mTrackedJobs.delete(userId, packageName);
         Timer timer = mPkgTimers.get(userId, packageName);
         if (timer != null) {
@@ -1008,7 +1008,7 @@
     }
 
     @VisibleForTesting
-    void incrementJobCount(final int userId, @NonNull final String packageName, int count) {
+    void incrementJobCountLocked(final int userId, @NonNull final String packageName, int count) {
         final long now = sElapsedRealtimeClock.millis();
         ExecutionStats[] appStats = mExecutionStatsCache.get(userId, packageName);
         if (appStats == null) {
@@ -1029,7 +1029,8 @@
         }
     }
 
-    private void incrementTimingSessionCount(final int userId, @NonNull final String packageName) {
+    private void incrementTimingSessionCountLocked(final int userId,
+            @NonNull final String packageName) {
         final long now = sElapsedRealtimeClock.millis();
         ExecutionStats[] appStats = mExecutionStatsCache.get(userId, packageName);
         if (appStats == null) {
@@ -1481,7 +1482,7 @@
             mRunningBgJobs.add(jobStatus);
             if (shouldTrackLocked()) {
                 mBgJobCount++;
-                incrementJobCount(mPkg.userId, mPkg.packageName, 1);
+                incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
                 if (mRunningBgJobs.size() == 1) {
                     // Started tracking the first job.
                     mStartTimeElapsed = sElapsedRealtimeClock.millis();
@@ -1534,7 +1535,7 @@
             // of jobs.
             // However, cancel the currently scheduled cutoff since it's not currently useful.
             cancelCutoff();
-            incrementTimingSessionCount(mPkg.userId, mPkg.packageName);
+            incrementTimingSessionCountLocked(mPkg.userId, mPkg.packageName);
         }
 
         /**
@@ -1581,7 +1582,7 @@
                     // repeatedly plugged in and unplugged, or an app changes foreground state
                     // very frequently, the job count for a package may be artificially high.
                     mBgJobCount = mRunningBgJobs.size();
-                    incrementJobCount(mPkg.userId, mPkg.packageName, mBgJobCount);
+                    incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);
                     // Starting the timer means that all cached execution stats are now
                     // incorrect.
                     invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING
index ec2d2e2..70c9087 100644
--- a/apex/media/framework/TEST_MAPPING
+++ b/apex/media/framework/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "CtsMediaParserTestCases"
+    },
+    {
+      "name": "CtsMediaParserHostSideTestCases"
     }
   ]
 }
diff --git a/api/Android.bp b/api/Android.bp
index a5def69..5ee41b7 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -59,6 +59,27 @@
 }
 
 genrule {
+    name: "frameworks-base-api-current.srcjar",
+    srcs: [
+        ":api-stubs-docs-non-updatable",
+        ":conscrypt.module.public.api{.public.stubs.source}",
+        ":framework-appsearch{.public.stubs.source}",
+        ":framework-graphics{.public.stubs.source}",
+        ":framework-media{.public.stubs.source}",
+        ":framework-mediaprovider{.public.stubs.source}",
+        ":framework-permission{.public.stubs.source}",
+        ":framework-sdkextensions{.public.stubs.source}",
+        ":framework-statsd{.public.stubs.source}",
+        ":framework-tethering{.public.stubs.source}",
+        ":framework-wifi{.public.stubs.source}",
+    ],
+    out: ["current.srcjar"],
+    tools: ["merge_zips"],
+    cmd: "$(location merge_zips) $(out) $(in)",
+    visibility: ["//visibility:private"], // Used by make module in //development, mind.
+}
+
+genrule {
     name: "frameworks-base-api-removed.txt",
     srcs: [
         ":conscrypt.module.public.api{.public.removed-api.txt}",
diff --git a/api/current.txt b/api/current.txt
index 1258e29..344e93b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5491,7 +5491,9 @@
     field public static final String CATEGORY_EMAIL = "email";
     field public static final String CATEGORY_ERROR = "err";
     field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
     field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_MISSED_CALL = "missed_call";
     field public static final String CATEGORY_NAVIGATION = "navigation";
     field public static final String CATEGORY_PROGRESS = "progress";
     field public static final String CATEGORY_PROMO = "promo";
@@ -5500,8 +5502,10 @@
     field public static final String CATEGORY_SERVICE = "service";
     field public static final String CATEGORY_SOCIAL = "social";
     field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_STOPWATCH = "stopwatch";
     field public static final String CATEGORY_SYSTEM = "sys";
     field public static final String CATEGORY_TRANSPORT = "transport";
+    field public static final String CATEGORY_WORKOUT = "workout";
     field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
@@ -23964,7 +23968,7 @@
     method public float getBearingAccuracyDegrees();
     method public long getElapsedRealtimeNanos();
     method public double getElapsedRealtimeUncertaintyNanos();
-    method public android.os.Bundle getExtras();
+    method @Deprecated public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
     method public String getProvider();
@@ -23993,7 +23997,7 @@
     method public void setBearingAccuracyDegrees(float);
     method public void setElapsedRealtimeNanos(long);
     method public void setElapsedRealtimeUncertaintyNanos(double);
-    method public void setExtras(android.os.Bundle);
+    method @Deprecated public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
     method public void setProvider(String);
@@ -24009,7 +24013,9 @@
   }
 
   public interface LocationListener {
+    method public default void onFlushComplete(int);
     method public void onLocationChanged(@NonNull android.location.Location);
+    method public default void onLocationChanged(@NonNull android.location.LocationResult);
     method public default void onProviderDisabled(@NonNull String);
     method public default void onProviderEnabled(@NonNull String);
     method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
@@ -24057,6 +24063,8 @@
     method public void removeTestProvider(@NonNull String);
     method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
     method public void removeUpdates(@NonNull android.app.PendingIntent);
+    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -24082,7 +24090,9 @@
     field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
     field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
     field public static final String GPS_PROVIDER = "gps";
+    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
     field public static final String KEY_LOCATION_CHANGED = "location";
+    field public static final String KEY_LOCATION_RESULT = "locationResult";
     field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
     field public static final String KEY_PROXIMITY_ENTERING = "entering";
     field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
@@ -24113,6 +24123,7 @@
     method public int describeContents();
     method @IntRange(from=1) public long getDurationMillis();
     method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
     method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
     method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
     method @IntRange(from=0) public long getMinUpdateIntervalMillis();
@@ -24132,12 +24143,25 @@
     method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
     method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
     method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
     method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
     method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
     method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
     method @NonNull public android.location.LocationRequest.Builder setQuality(int);
   }
 
+  public final class LocationResult implements android.os.Parcelable {
+    method @NonNull public java.util.List<android.location.Location> asList();
+    method @NonNull public static android.location.LocationResult create(@NonNull android.location.Location);
+    method @NonNull public static android.location.LocationResult create(@NonNull java.util.List<android.location.Location>);
+    method public int describeContents();
+    method @NonNull public android.location.Location get(@IntRange(from=0) int);
+    method @NonNull public android.location.Location getLastLocation();
+    method @IntRange(from=1) public int size();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationResult> CREATOR;
+  }
+
   public interface OnNmeaMessageListener {
     method public void onNmeaMessage(String, long);
   }
@@ -28835,7 +28859,6 @@
   public final class MediaController {
     ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
-    method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController);
     method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent);
     method @Nullable public android.os.Bundle getExtras();
     method public long getFlags();
@@ -52693,6 +52716,7 @@
 
   public static final class Display.Mode implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public float[] getAlternativeRefreshRates();
     method public int getModeId();
     method public int getPhysicalHeight();
     method public int getPhysicalWidth();
@@ -55139,6 +55163,7 @@
     method @Deprecated public static int getMaximumDrawingCacheSize();
     method @Deprecated public static int getMaximumFlingVelocity();
     method @Deprecated public static int getMinimumFlingVelocity();
+    method public static int getMultiPressTimeout();
     method public static int getPressedStateDuration();
     method @FloatRange(from=1.0) public float getScaledAmbiguousGestureMultiplier();
     method public int getScaledDoubleTapSlop();
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
deleted file mode 100644
index 1a65064..0000000
--- a/api/module-lib-current.txt
+++ /dev/null
@@ -1,229 +0,0 @@
-// Signature format: 2.0
-package android.app {
-
-  public class ActivityManager {
-    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
-    method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
-  }
-
-  public class AppOpsManager {
-    field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
-  }
-
-  public abstract class HomeVisibilityListener {
-    ctor public HomeVisibilityListener();
-    method public abstract void onHomeVisibilityChanged(boolean);
-  }
-
-  public class NotificationManager {
-    method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
-    field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
-  }
-
-  public class StatusBarManager {
-    method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean);
-  }
-
-}
-
-package android.app.role {
-
-  public final class RoleManager {
-    method @Nullable public String getSmsRoleHolder(int);
-  }
-
-}
-
-package android.content.rollback {
-
-  public class RollbackManagerFrameworkInitializer {
-    method public static void initialize();
-  }
-
-}
-
-package android.graphics {
-
-  public final class Compatibility {
-    method public static void setTargetSdkVersion(int);
-  }
-
-  public final class ImageDecoder implements java.lang.AutoCloseable {
-    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @Nullable android.content.res.Resources);
-  }
-
-}
-
-package android.media {
-
-  public class AudioManager {
-    method public void adjustStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
-    method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
-    method public void setStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
-    field public static final int FLAG_FROM_KEY = 4096; // 0x1000
-  }
-
-  public class MediaMetadataRetriever implements java.lang.AutoCloseable {
-    field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
-  }
-
-  @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
-    ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public static <T extends android.os.Parcelable> android.media.MediaParceledListSlice<T> emptyList();
-    method @Deprecated public java.util.List<T> getList();
-    method @Deprecated public void setInlineCountLimit(int);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.ClassLoaderCreator<android.media.MediaParceledListSlice> CREATOR;
-  }
-
-}
-
-package android.media.session {
-
-  public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
-    ctor public MediaController.PlaybackInfo(int, int, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.media.AudioAttributes, @Nullable String);
-  }
-
-  public final class MediaSession {
-    field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
-  }
-
-  public static final class MediaSession.Token implements android.os.Parcelable {
-    method public int getUid();
-  }
-
-  public final class MediaSessionManager {
-    method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
-    method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
-    method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
-    method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
-    method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
-    method public void registerRemoteVolumeControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.RemoteVolumeControllerCallback);
-    method public void unregisterRemoteVolumeControllerCallback(@NonNull android.media.session.MediaSessionManager.RemoteVolumeControllerCallback);
-    field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
-    field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
-  }
-
-  public static interface MediaSessionManager.RemoteVolumeControllerCallback {
-    method public void onSessionChanged(@Nullable android.media.session.MediaSession.Token);
-    method public void onVolumeChanged(@NonNull android.media.session.MediaSession.Token, int);
-  }
-
-  public final class PlaybackState implements android.os.Parcelable {
-    method public boolean isActiveState();
-  }
-
-}
-
-package android.net {
-
-  public final class TetheringConstants {
-    field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
-    field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
-    field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
-    field public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-    field public static final String EXTRA_SET_ALARM = "extraSetAlarm";
-  }
-
-  public class TetheringManager {
-    ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier<android.os.IBinder>);
-    method public int getLastTetherError(@NonNull String);
-    method @NonNull public String[] getTetherableBluetoothRegexs();
-    method @NonNull public String[] getTetherableIfaces();
-    method @NonNull public String[] getTetherableUsbRegexs();
-    method @NonNull public String[] getTetherableWifiRegexs();
-    method @NonNull public String[] getTetheredIfaces();
-    method @NonNull public String[] getTetheringErroredIfaces();
-    method public boolean isTetheringSupported();
-    method public boolean isTetheringSupported(@NonNull String);
-    method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
-    method @Deprecated public int setUsbTethering(boolean);
-    method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
-    method @Deprecated public int tether(@NonNull String);
-    method @Deprecated public int untether(@NonNull String);
-  }
-
-  public static interface TetheringManager.TetheringEventCallback {
-    method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-  }
-
-  public static class TetheringManager.TetheringInterfaceRegexps {
-    method @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
-  }
-
-}
-
-package android.os {
-
-  public class Binder implements android.os.IBinder {
-    method public final void markVintfStability();
-  }
-
-  public interface Parcelable {
-    method public default int getStability();
-  }
-
-  public class StatsFrameworkInitializer {
-    method public static void registerServiceWrappers();
-    method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
-  }
-
-  public class StatsServiceManager {
-    method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
-    method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
-    method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsdServiceRegisterer();
-  }
-
-  public static class StatsServiceManager.ServiceNotFoundException extends java.lang.Exception {
-    ctor public StatsServiceManager.ServiceNotFoundException(@NonNull String);
-  }
-
-  public static final class StatsServiceManager.ServiceRegisterer {
-    method @Nullable public android.os.IBinder get();
-    method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
-  }
-
-}
-
-package android.provider {
-
-  public final class DeviceConfig {
-    field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager";
-    field public static final String NAMESPACE_APP_STANDBY = "app_standby";
-    field public static final String NAMESPACE_DEVICE_IDLE = "device_idle";
-  }
-
-}
-
-package android.telephony {
-
-  public abstract class CellSignalStrength {
-    method public static int getNumSignalStrengthLevels();
-  }
-
-  public class TelephonyManager {
-    method @NonNull public static int[] getAllNetworkTypes();
-  }
-
-}
-
-package android.util {
-
-  public class AtomicFile {
-    ctor public AtomicFile(@NonNull java.io.File, @Nullable android.util.SystemConfigFileCommitEventLogger);
-  }
-
-  public final class Log {
-    method public static int logToRadioBuffer(int, @Nullable String, @Nullable String);
-  }
-
-  public class SystemConfigFileCommitEventLogger {
-    ctor public SystemConfigFileCommitEventLogger(@NonNull String);
-    method public void setStartTime(long);
-  }
-
-}
-
diff --git a/api/system-current.txt b/api/system-current.txt
index 3321677..0eaebce 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3841,7 +3841,8 @@
     method public boolean hasMeasurementCorrectionsReflectingPane();
     method public boolean hasMeasurements();
     method public boolean hasNavMessages();
-    method public boolean hasSatelliteBlacklist();
+    method @Deprecated public boolean hasSatelliteBlacklist();
+    method public boolean hasSatelliteBlocklist();
   }
 
   public final class GnssMeasurementCorrections implements android.os.Parcelable {
@@ -4169,17 +4170,17 @@
   }
 
   public class LocationManager {
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
     method @Nullable public String getExtraLocationControllerPackage();
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
+    method @Deprecated public int getGnssBatchSize();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -4188,7 +4189,7 @@
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
   }
 
   public final class LocationRequest implements android.os.Parcelable {
@@ -4235,6 +4236,10 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
   }
 
+  public final class LocationResult implements android.os.Parcelable {
+    method @NonNull public static android.location.LocationResult wrap(@NonNull android.location.Location);
+  }
+
 }
 
 package android.media {
@@ -5107,7 +5112,9 @@
     field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
     field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
     field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
+    field public static final int INVALID_FRONTEND_ID = -1; // 0xffffffff
     field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+    field @NonNull public static final byte[] INVALID_KEYTOKEN;
     field public static final int INVALID_LTS_ID = -1; // 0xffffffff
     field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
     field public static final int INVALID_STREAM_ID = 65535; // 0xffff
@@ -5411,6 +5418,7 @@
     method public int getMpuSequenceNumber();
     method public long getPts();
     method public int getScHevcIndexMask();
+    method public int getTsIndexMask();
   }
 
   public class PesEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5439,6 +5447,11 @@
     field public static final int INDEX_TYPE_NONE = 0; // 0x0
     field public static final int INDEX_TYPE_SC = 1; // 0x1
     field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
+    field public static final int MPT_INDEX_AUDIO = 262144; // 0x40000
+    field public static final int MPT_INDEX_MPT = 65536; // 0x10000
+    field public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO = 1048576; // 0x100000
+    field public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO = 524288; // 0x80000
+    field public static final int MPT_INDEX_VIDEO = 131072; // 0x20000
     field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
     field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
     field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
@@ -5462,6 +5475,7 @@
     field public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = 16; // 0x10
     field public static final int TS_INDEX_DISCONTINUITY_INDICATOR = 32; // 0x20
     field public static final int TS_INDEX_FIRST_PACKET = 1; // 0x1
+    field public static final int TS_INDEX_INVALID = 0; // 0x0
     field public static final int TS_INDEX_OPCR_FLAG = 512; // 0x200
     field public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = 2; // 0x2
     field public static final int TS_INDEX_PCR_FLAG = 256; // 0x100
@@ -5814,7 +5828,8 @@
 
   public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
     method public int getAnnexCapability();
-    method public int getFecCapability();
+    method public long getCodeRateCapability();
+    method @Deprecated public int getFecCapability();
     method public int getModulationCapability();
   }
 
@@ -6175,6 +6190,7 @@
     method public int getPer();
     method public int getPerBer();
     method public int getPlpId();
+    method public int getRollOff();
     method public int getSignalQuality();
     method public int getSignalStrength();
     method public int getSnr();
@@ -6186,8 +6202,11 @@
     method public int getUec();
     method public boolean isDemodLocked();
     method public boolean isEwbs();
+    method public boolean isLinear();
     method public boolean isLnaOn();
+    method public boolean isMisoEnabled();
     method public boolean isRfLocked();
+    method public boolean isShortFramesEnabled();
     field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
     field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15
     field public static final int FRONTEND_STATUS_TYPE_BANDWIDTH = 25; // 0x19
@@ -6202,6 +6221,9 @@
     field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
     field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
     field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
+    field public static final int FRONTEND_STATUS_TYPE_IS_LINEAR = 35; // 0x23
+    field public static final int FRONTEND_STATUS_TYPE_IS_MISO = 34; // 0x22
+    field public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES = 36; // 0x24
     field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
     field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
     field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
@@ -6212,6 +6234,7 @@
     field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
     field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
     field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14
+    field public static final int FRONTEND_STATUS_TYPE_ROLL_OFF = 33; // 0x21
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
     field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
@@ -10064,6 +10087,32 @@
 
 }
 
+package android.service.attestation {
+
+  public abstract class ImpressionAttestationService extends android.app.Service {
+    ctor public ImpressionAttestationService();
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
+    method public abstract int onVerifyImpressionToken(@NonNull android.service.attestation.ImpressionToken);
+    field public static final int VERIFICATION_STATUS_APP_DECLARED = 2; // 0x2
+    field public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; // 0x1
+    field public static final int VERIFICATION_STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  public final class ImpressionToken implements android.os.Parcelable {
+    ctor public ImpressionToken(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]);
+    method public int describeContents();
+    method @NonNull public android.graphics.Rect getBoundsInWindow();
+    method @NonNull public String getHashingAlgorithm();
+    method @NonNull public byte[] getHmac();
+    method @NonNull public byte[] getImageHash();
+    method public long getScreenshotTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.attestation.ImpressionToken> CREATOR;
+  }
+
+}
+
 package android.service.autofill {
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
@@ -11818,6 +11867,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
     method public String getCdmaPrlVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode();
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
@@ -11890,6 +11941,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
@@ -11935,6 +11988,9 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+    field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1
+    field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0
+    field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3
@@ -12086,7 +12142,7 @@
     method public int getMtuV6();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
     method public int getProtocolType();
-    method public long getRetryIntervalMillis();
+    method public long getRetryDurationMillis();
     method @Deprecated public int getSuggestedRetryTime();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -12099,7 +12155,7 @@
     field public static final int LINK_STATUS_DORMANT = 1; // 0x1
     field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
     field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
-    field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff
+    field public static final int RETRY_DURATION_UNDEFINED = -1; // 0xffffffff
   }
 
   public static final class DataCallResponse.Builder {
@@ -12118,7 +12174,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
-    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
     method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
   }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b270a52..7071155 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -158,7 +158,7 @@
         AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
         ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
         BootSequenceReported boot_sequence_reported = 57;
-        DaveyOccurred davey_occurred = 58 [(module) = "statsd"];
+        DaveyOccurred davey_occurred = 58 [(module) = "statsd", deprecated = true];
         OverlayStateChanged overlay_state_changed =
                 59 [(module) = "framework", (module) = "statsdtest"];
         ForegroundServiceStateChanged foreground_service_state_changed
diff --git a/core/api/current.txt b/core/api/current.txt
index 95a06fc1..9562715 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5491,7 +5491,9 @@
     field public static final String CATEGORY_EMAIL = "email";
     field public static final String CATEGORY_ERROR = "err";
     field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
     field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_MISSED_CALL = "missed_call";
     field public static final String CATEGORY_NAVIGATION = "navigation";
     field public static final String CATEGORY_PROGRESS = "progress";
     field public static final String CATEGORY_PROMO = "promo";
@@ -5500,8 +5502,10 @@
     field public static final String CATEGORY_SERVICE = "service";
     field public static final String CATEGORY_SOCIAL = "social";
     field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_STOPWATCH = "stopwatch";
     field public static final String CATEGORY_SYSTEM = "sys";
     field public static final String CATEGORY_TRANSPORT = "transport";
+    field public static final String CATEGORY_WORKOUT = "workout";
     field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
@@ -23946,7 +23950,7 @@
     method public float getBearingAccuracyDegrees();
     method public long getElapsedRealtimeNanos();
     method public double getElapsedRealtimeUncertaintyNanos();
-    method public android.os.Bundle getExtras();
+    method @Deprecated public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
     method public String getProvider();
@@ -23975,7 +23979,7 @@
     method public void setBearingAccuracyDegrees(float);
     method public void setElapsedRealtimeNanos(long);
     method public void setElapsedRealtimeUncertaintyNanos(double);
-    method public void setExtras(android.os.Bundle);
+    method @Deprecated public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
     method public void setProvider(String);
@@ -23991,7 +23995,9 @@
   }
 
   public interface LocationListener {
+    method public default void onFlushComplete(int);
     method public void onLocationChanged(@NonNull android.location.Location);
+    method public default void onLocationChanged(@NonNull android.location.LocationResult);
     method public default void onProviderDisabled(@NonNull String);
     method public default void onProviderEnabled(@NonNull String);
     method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
@@ -24039,6 +24045,8 @@
     method public void removeTestProvider(@NonNull String);
     method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
     method public void removeUpdates(@NonNull android.app.PendingIntent);
+    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -24064,7 +24072,9 @@
     field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
     field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
     field public static final String GPS_PROVIDER = "gps";
+    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
     field public static final String KEY_LOCATION_CHANGED = "location";
+    field public static final String KEY_LOCATION_RESULT = "locationResult";
     field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
     field public static final String KEY_PROXIMITY_ENTERING = "entering";
     field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
@@ -24095,6 +24105,7 @@
     method public int describeContents();
     method @IntRange(from=1) public long getDurationMillis();
     method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
     method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
     method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
     method @IntRange(from=0) public long getMinUpdateIntervalMillis();
@@ -24114,12 +24125,25 @@
     method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
     method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
     method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
     method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
     method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
     method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
     method @NonNull public android.location.LocationRequest.Builder setQuality(int);
   }
 
+  public final class LocationResult implements android.os.Parcelable {
+    method @NonNull public java.util.List<android.location.Location> asList();
+    method @NonNull public static android.location.LocationResult create(@NonNull android.location.Location);
+    method @NonNull public static android.location.LocationResult create(@NonNull java.util.List<android.location.Location>);
+    method public int describeContents();
+    method @NonNull public android.location.Location get(@IntRange(from=0) int);
+    method @NonNull public android.location.Location getLastLocation();
+    method @IntRange(from=1) public int size();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationResult> CREATOR;
+  }
+
   public interface OnNmeaMessageListener {
     method public void onNmeaMessage(String, long);
   }
@@ -28596,7 +28620,6 @@
   public final class MediaController {
     ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token);
     method public void adjustVolume(int, int);
-    method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController);
     method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent);
     method @Nullable public android.os.Bundle getExtras();
     method public long getFlags();
@@ -50798,6 +50821,7 @@
 
   public static final class Display.Mode implements android.os.Parcelable {
     method public int describeContents();
+    method @NonNull public float[] getAlternativeRefreshRates();
     method public int getModeId();
     method public int getPhysicalHeight();
     method public int getPhysicalWidth();
@@ -53244,6 +53268,7 @@
     method @Deprecated public static int getMaximumDrawingCacheSize();
     method @Deprecated public static int getMaximumFlingVelocity();
     method @Deprecated public static int getMinimumFlingVelocity();
+    method public static int getMultiPressTimeout();
     method public static int getPressedStateDuration();
     method @FloatRange(from=1.0) public float getScaledAmbiguousGestureMultiplier();
     method public int getScaledDoubleTapSlop();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 40ac3cd..7085f7b 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -4,6 +4,7 @@
   public class ActivityManager {
     method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
     method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
   }
 
   public class AppOpsManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ede08d5..ed3b7de 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3781,7 +3781,8 @@
     method public boolean hasMeasurementCorrectionsReflectingPane();
     method public boolean hasMeasurements();
     method public boolean hasNavMessages();
-    method public boolean hasSatelliteBlacklist();
+    method @Deprecated public boolean hasSatelliteBlacklist();
+    method public boolean hasSatelliteBlocklist();
   }
 
   public final class GnssMeasurementCorrections implements android.os.Parcelable {
@@ -4109,17 +4110,17 @@
   }
 
   public class LocationManager {
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
     method @Nullable public String getExtraLocationControllerPackage();
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
+    method @Deprecated public int getGnssBatchSize();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -4128,7 +4129,7 @@
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
   }
 
   public final class LocationRequest implements android.os.Parcelable {
@@ -4175,6 +4176,10 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
   }
 
+  public final class LocationResult implements android.os.Parcelable {
+    method @NonNull public static android.location.LocationResult wrap(@NonNull android.location.Location);
+  }
+
 }
 
 package android.media {
@@ -5047,7 +5052,9 @@
     field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
     field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
     field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
+    field public static final int INVALID_FRONTEND_ID = -1; // 0xffffffff
     field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+    field @NonNull public static final byte[] INVALID_KEYTOKEN;
     field public static final int INVALID_LTS_ID = -1; // 0xffffffff
     field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
     field public static final int INVALID_STREAM_ID = 65535; // 0xffff
@@ -5351,6 +5358,7 @@
     method public int getMpuSequenceNumber();
     method public long getPts();
     method public int getScHevcIndexMask();
+    method public int getTsIndexMask();
   }
 
   public class PesEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5379,6 +5387,11 @@
     field public static final int INDEX_TYPE_NONE = 0; // 0x0
     field public static final int INDEX_TYPE_SC = 1; // 0x1
     field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
+    field public static final int MPT_INDEX_AUDIO = 262144; // 0x40000
+    field public static final int MPT_INDEX_MPT = 65536; // 0x10000
+    field public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO = 1048576; // 0x100000
+    field public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO = 524288; // 0x80000
+    field public static final int MPT_INDEX_VIDEO = 131072; // 0x20000
     field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
     field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
     field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
@@ -5402,6 +5415,7 @@
     field public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = 16; // 0x10
     field public static final int TS_INDEX_DISCONTINUITY_INDICATOR = 32; // 0x20
     field public static final int TS_INDEX_FIRST_PACKET = 1; // 0x1
+    field public static final int TS_INDEX_INVALID = 0; // 0x0
     field public static final int TS_INDEX_OPCR_FLAG = 512; // 0x200
     field public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = 2; // 0x2
     field public static final int TS_INDEX_PCR_FLAG = 256; // 0x100
@@ -5754,7 +5768,8 @@
 
   public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
     method public int getAnnexCapability();
-    method public int getFecCapability();
+    method public long getCodeRateCapability();
+    method @Deprecated public int getFecCapability();
     method public int getModulationCapability();
   }
 
@@ -6115,6 +6130,7 @@
     method public int getPer();
     method public int getPerBer();
     method public int getPlpId();
+    method public int getRollOff();
     method public int getSignalQuality();
     method public int getSignalStrength();
     method public int getSnr();
@@ -6126,8 +6142,11 @@
     method public int getUec();
     method public boolean isDemodLocked();
     method public boolean isEwbs();
+    method public boolean isLinear();
     method public boolean isLnaOn();
+    method public boolean isMisoEnabled();
     method public boolean isRfLocked();
+    method public boolean isShortFramesEnabled();
     field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
     field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15
     field public static final int FRONTEND_STATUS_TYPE_BANDWIDTH = 25; // 0x19
@@ -6142,6 +6161,9 @@
     field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
     field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
     field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
+    field public static final int FRONTEND_STATUS_TYPE_IS_LINEAR = 35; // 0x23
+    field public static final int FRONTEND_STATUS_TYPE_IS_MISO = 34; // 0x22
+    field public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES = 36; // 0x24
     field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
     field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
     field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
@@ -6152,6 +6174,7 @@
     field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
     field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
     field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14
+    field public static final int FRONTEND_STATUS_TYPE_ROLL_OFF = 33; // 0x21
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
     field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
@@ -8905,6 +8928,32 @@
 
 }
 
+package android.service.attestation {
+
+  public abstract class ImpressionAttestationService extends android.app.Service {
+    ctor public ImpressionAttestationService();
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
+    method public abstract int onVerifyImpressionToken(@NonNull android.service.attestation.ImpressionToken);
+    field public static final int VERIFICATION_STATUS_APP_DECLARED = 2; // 0x2
+    field public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; // 0x1
+    field public static final int VERIFICATION_STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  public final class ImpressionToken implements android.os.Parcelable {
+    ctor public ImpressionToken(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]);
+    method public int describeContents();
+    method @NonNull public android.graphics.Rect getBoundsInWindow();
+    method @NonNull public String getHashingAlgorithm();
+    method @NonNull public byte[] getHmac();
+    method @NonNull public byte[] getImageHash();
+    method public long getScreenshotTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.attestation.ImpressionToken> CREATOR;
+  }
+
+}
+
 package android.service.autofill {
 
   public abstract class AutofillFieldClassificationService extends android.app.Service {
@@ -10659,6 +10708,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
     method public String getCdmaPrlVersion();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode();
     method public int getCurrentPhoneType();
     method public int getCurrentPhoneType(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
@@ -10731,6 +10782,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
@@ -10776,6 +10829,9 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+    field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1
+    field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0
+    field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1
     field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3
@@ -10927,7 +10983,7 @@
     method public int getMtuV6();
     method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
     method public int getProtocolType();
-    method public long getRetryIntervalMillis();
+    method public long getRetryDurationMillis();
     method @Deprecated public int getSuggestedRetryTime();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -10940,7 +10996,7 @@
     field public static final int LINK_STATUS_DORMANT = 1; // 0x1
     field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
     field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
-    field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff
+    field public static final int RETRY_DURATION_UNDEFINED = -1; // 0xffffffff
   }
 
   public static final class DataCallResponse.Builder {
@@ -10959,7 +11015,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
-    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
     method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1fdb3e4..db45ec5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -91,6 +91,7 @@
     method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+    method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
     field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
     field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
     field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 75ffb280..fc95718 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2702,12 +2702,18 @@
      */
     public void reportFullyDrawn() {
         if (mDoReportFullyDrawn) {
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                        "reportFullyDrawn() for " + mComponent.toShortString());
+            }
             mDoReportFullyDrawn = false;
             try {
                 ActivityTaskManager.getService().reportActivityFullyDrawn(
                         mToken, mRestoredFromBundle);
                 VMRuntime.getRuntime().notifyStartupCompleted();
             } catch (RemoteException e) {
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             }
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index bd51fc5..f9970dd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4200,15 +4200,18 @@
     }
 
     /**
-     * Updates mcc mnc configuration and applies changes to the entire system.
+     * Updates the MCC (Mobile Country Code) and MNC (Mobile Network Code) in the
+     * system configuration.
      *
-     * @param mcc mcc configuration to update.
-     * @param mnc mnc configuration to update.
+     * @param mcc The new MCC.
+     * @param mnc The new MNC.
      * @throws RemoteException; IllegalArgumentException if mcc or mnc is null;
      * @return Returns {@code true} if the configuration was updated successfully;
      *         {@code false} otherwise.
      * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
     @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION)
     public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) {
         if (mcc == null || mnc == null) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b292094..0f6ebf2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4972,15 +4972,8 @@
     }
 
     private void relaunchAllActivities(boolean preserveWindows) {
-        for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-            final ActivityClientRecord r = entry.getValue();
-            // Schedule relaunch the activity if it is not a local object or finishing.
-            if (!r.activity.mFinished && !(r.token instanceof Binder)) {
-                if (preserveWindows && r.window != null) {
-                    r.mPreserveWindow = true;
-                }
-                scheduleRelaunchActivity(entry.getKey());
-            }
+        for (int i = mActivities.size() - 1; i >= 0; i--) {
+            scheduleRelaunchActivityIfPossible(mActivities.valueAt(i), preserveWindows);
         }
     }
 
@@ -5349,15 +5342,31 @@
         }
     }
 
+    void scheduleRelaunchActivity(IBinder token) {
+        final ActivityClientRecord r = mActivities.get(token);
+        if (r != null) {
+            scheduleRelaunchActivityIfPossible(r, !r.stopped /* preserveWindow */);
+        }
+    }
+
     /**
      * Post a message to relaunch the activity. We do this instead of launching it immediately,
      * because this will destroy the activity from which it was called and interfere with the
      * lifecycle changes it was going through before. We need to make sure that we have finished
      * handling current transaction item before relaunching the activity.
      */
-    void scheduleRelaunchActivity(IBinder token) {
-        mH.removeMessages(H.RELAUNCH_ACTIVITY, token);
-        sendMessage(H.RELAUNCH_ACTIVITY, token);
+    private void scheduleRelaunchActivityIfPossible(@NonNull ActivityClientRecord r,
+            boolean preserveWindow) {
+        if (r.activity.mFinished || r.token instanceof Binder) {
+            // Do not schedule relaunch if the activity is finishing or not a local object (e.g.
+            // created by ActivtiyGroup that server side doesn't recognize it).
+            return;
+        }
+        if (preserveWindow && r.window != null) {
+            r.mPreserveWindow = true;
+        }
+        mH.removeMessages(H.RELAUNCH_ACTIVITY, r.token);
+        sendMessage(H.RELAUNCH_ACTIVITY, r.token);
     }
 
     /** Performs the activity relaunch locally vs. requesting from system-server. */
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 26b4234..d6cf8ff 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7618,16 +7618,18 @@
                 mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
 
         final String voiceRecognitionServicePackageName =
-                voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
-                        voiceRecognitionComponent).getPackageName() : "";
+                getComponentPackageNameFromString(voiceRecognitionComponent);
         final String voiceInteractionServicePackageName =
-                voiceInteractionComponent != null ? ComponentName.unflattenFromString(
-                        voiceInteractionComponent).getPackageName() : "";
-
+                getComponentPackageNameFromString(voiceInteractionComponent);
         return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
                 voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
     }
 
+    private String getComponentPackageNameFromString(String from) {
+        ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+        return componentName != null ? componentName.getPackageName() : "";
+    }
+
     /**
      * Do a quick check for whether an application might be able to perform an operation.
      * This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 560b5be..86625d3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -98,6 +98,8 @@
     void unregisterUidObserver(in IUidObserver observer);
     boolean isUidActive(int uid, String callingPackage);
     int getUidProcessState(int uid, in String callingPackage);
+    @UnsupportedAppUsage
+    int checkPermission(in String permission, int pid, int uid);
     // =============== End of transactions used on native side as well ============================
 
     // Special low-level communication with activity manager.
@@ -215,8 +217,6 @@
     void setProcessLimit(int max);
     @UnsupportedAppUsage
     int getProcessLimit();
-    @UnsupportedAppUsage
-    int checkPermission(in String permission, int pid, int uid);
     int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId,
             in IBinder callerToken);
     void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8cafaa8..4c08e75 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -897,6 +897,26 @@
     public static final String CATEGORY_CAR_INFORMATION = "car_information";
 
     /**
+     * Notification category: tracking a user's workout.
+     */
+    public static final String CATEGORY_WORKOUT = "workout";
+
+    /**
+     * Notification category: temporarily sharing location.
+     */
+    public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+
+    /**
+     * Notification category: running stopwatch.
+     */
+    public static final String CATEGORY_STOPWATCH = "stopwatch";
+
+    /**
+     * Notification category: missed call.
+     */
+    public static final String CATEGORY_MISSED_CALL = "missed_call";
+
+    /**
      * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
      * that best describes this Notification.  May be used by the system for ranking and filtering.
      */
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 6d92d3e..72a66ed 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.parsing.ParsingPackageUtils.validateName;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
 import android.content.pm.PackageInfo;
@@ -501,10 +502,10 @@
 
         final String packageName = attrs.getAttributeValue(null, "package");
         if (!"android".equals(packageName)) {
-            final String error = PackageParser.validateName(packageName, true, true);
-            if (error != null) {
+            final ParseResult<?> nameResult = validateName(input, packageName, true, true);
+            if (nameResult.isError()) {
                 return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                        "Invalid manifest package: " + error);
+                        "Invalid manifest package: " + nameResult.getErrorMessage());
             }
         }
 
@@ -513,10 +514,10 @@
             if (splitName.length() == 0) {
                 splitName = null;
             } else {
-                final String error = PackageParser.validateName(splitName, false, false);
-                if (error != null) {
+                final ParseResult<?> nameResult = validateName(input, splitName, false, false);
+                if (nameResult.isError()) {
                     return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
-                            "Invalid manifest split: " + error);
+                            "Invalid manifest split: " + nameResult.getErrorMessage());
                 }
             }
         }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b936c63..6196854 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -130,6 +130,12 @@
     private static final String TAG = ParsingUtils.TAG;
 
     /**
+     * For those names would be used as a part of the file name. Limits size to 223 and reserves 32
+     * for the OS.
+     */
+    private static final int MAX_FILE_NAME_SIZE = 223;
+
+    /**
      * @see #parseDefault(ParseInput, File, int, boolean)
      */
     @NonNull
@@ -2686,7 +2692,16 @@
         }
     }
 
-    private static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
+    /**
+     * Check if the given name is valid.
+     *
+     * @param name The name to check.
+     * @param requireSeparator {@code true} if the name requires containing a separator at least.
+     * @param requireFilename {@code true} to apply file name validation to the given name. It also
+     *                        limits length of the name to the {@link #MAX_FILE_NAME_SIZE}.
+     * @return Success if it's valid.
+     */
+    public static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
             boolean requireFilename) {
         final int N = name.length();
         boolean hasSep = false;
@@ -2709,8 +2724,12 @@
             }
             return input.error("bad character '" + c + "'");
         }
-        if (requireFilename && !FileUtils.isValidExtFilename(name)) {
-            return input.error("Invalid filename");
+        if (requireFilename) {
+            if (!FileUtils.isValidExtFilename(name)) {
+                return input.error("Invalid filename");
+            } else if (N > MAX_FILE_NAME_SIZE) {
+                return input.error("the length of the name is greater than " + MAX_FILE_NAME_SIZE);
+            }
         }
         return hasSep || !requireSeparator
                 ? input.success(null)
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
index cfefc016..d65f8ff 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -16,6 +16,8 @@
 
 package android.content.pm.parsing.component;
 
+import static android.content.pm.parsing.ParsingPackageUtils.validateName;
+
 import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -118,17 +120,19 @@
                         + ": must be at least two characters");
             }
             String subName = proc.substring(1);
-            String nameError = PackageParser.validateName(subName, false, false);
-            if (nameError != null) {
+            final ParseResult<?> nameResult = validateName(input, subName, false, false);
+            if (nameResult.isError()) {
                 return input.error("Invalid " + type + " name " + proc + " in package " + pkg
-                        + ": " + nameError);
+                        + ": " + nameResult.getErrorMessage());
             }
             return input.success(pkg + proc);
         }
-        String nameError = PackageParser.validateName(proc, true, false);
-        if (nameError != null && !"system".equals(proc)) {
-            return input.error("Invalid " + type + " name " + proc + " in package " + pkg
-                    + ": " + nameError);
+        if (!"system".equals(proc)) {
+            final ParseResult<?> nameResult = validateName(input, proc, true, false);
+            if (nameResult.isError()) {
+                return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+                        + ": " + nameResult.getErrorMessage());
+            }
         }
         return input.success(proc);
     }
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index 0778943..6a8e3f9 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -36,12 +36,16 @@
     public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
 
     /**
-     * Prefer networks in order: NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_OEM_PAID, default.
+     * If an unmetered network is available, use it.
+     * Otherwise, if a network with the OEM_PAID capability is available, use it.
+     * Otherwise, use the general default network.
      */
     public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1;
 
     /**
-     * Prefer networks in order: NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_OEM_PAID.
+     * If an unmetered network is available, use it.
+     * Otherwise, if a network with the OEM_PAID capability is available, use it.
+     * Otherwise, the app doesn't get a network.
      */
     public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
 
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index f552aaa..c9ebc1b 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -34,13 +34,14 @@
  * @hide
  * @see VibrationEffect
  */
+@SuppressWarnings({"ParcelNotFinal", "ParcelCreator"}) // Parcel only extended here.
 public abstract class CombinedVibrationEffect implements Parcelable {
     private static final int PARCEL_TOKEN_MONO = 1;
     private static final int PARCEL_TOKEN_STEREO = 2;
     private static final int PARCEL_TOKEN_SEQUENTIAL = 3;
 
-    /** @hide to prevent subclassing from outside of the framework */
-    public CombinedVibrationEffect() {
+    /** Prevent subclassing from outside of the framework. */
+    CombinedVibrationEffect() {
     }
 
     /**
@@ -113,7 +114,7 @@
          * @see VibrationEffect#createOneShot(long, int)
          */
         @NonNull
-        public SyncedCombination addVibrator(int vibratorId, VibrationEffect effect) {
+        public SyncedCombination addVibrator(int vibratorId, @NonNull VibrationEffect effect) {
             mEffects.put(vibratorId, effect);
             return this;
         }
@@ -256,11 +257,11 @@
     public static final class Mono extends CombinedVibrationEffect {
         private final VibrationEffect mEffect;
 
-        public Mono(Parcel in) {
+        Mono(Parcel in) {
             mEffect = VibrationEffect.CREATOR.createFromParcel(in);
         }
 
-        public Mono(@NonNull VibrationEffect effect) {
+        Mono(@NonNull VibrationEffect effect) {
             mEffect = effect;
         }
 
@@ -327,7 +328,7 @@
         /** Mapping vibrator ids to effects. */
         private final SparseArray<VibrationEffect> mEffects;
 
-        public Stereo(Parcel in) {
+        Stereo(Parcel in) {
             int size = in.readInt();
             mEffects = new SparseArray<>(size);
             for (int i = 0; i < size; i++) {
@@ -336,7 +337,7 @@
             }
         }
 
-        public Stereo(@NonNull SparseArray<VibrationEffect> effects) {
+        Stereo(@NonNull SparseArray<VibrationEffect> effects) {
             mEffects = new SparseArray<>(effects.size());
             for (int i = 0; i < effects.size(); i++) {
                 mEffects.put(effects.keyAt(i), effects.valueAt(i));
@@ -422,7 +423,7 @@
         private final List<CombinedVibrationEffect> mEffects;
         private final List<Integer> mDelays;
 
-        public Sequential(Parcel in) {
+        Sequential(Parcel in) {
             int size = in.readInt();
             mEffects = new ArrayList<>(size);
             mDelays = new ArrayList<>(size);
@@ -432,7 +433,7 @@
             }
         }
 
-        public Sequential(@NonNull List<CombinedVibrationEffect> effects,
+        Sequential(@NonNull List<CombinedVibrationEffect> effects,
                 @NonNull List<Integer> delays) {
             mEffects = new ArrayList<>(effects);
             mDelays = new ArrayList<>(delays);
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index ded9be5..ab74199 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -60,7 +60,7 @@
      * uses reflection to read this whenever text is selected (http://b/36095274).
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(trackingBug = 172649311)
     public static final int PROP_NAME_MAX = Integer.MAX_VALUE;
 
     /** @hide */
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index f82cc22..0f2a9f2 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -413,7 +413,7 @@
      *
      * @hide
      */
-    public abstract VibrationEffect resolve(int defaultAmplitude);
+    public abstract <T extends VibrationEffect> T resolve(int defaultAmplitude);
 
     /**
      * Scale the vibration effect intensity with the given constraints.
@@ -425,7 +425,7 @@
      *
      * @hide
      */
-    public abstract VibrationEffect scale(float scaleFactor);
+    public abstract <T extends VibrationEffect> T scale(float scaleFactor);
 
     /**
      * Scale given vibration intensity by the given factor.
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index e0927eb..6588b57 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -435,6 +435,7 @@
                 for (WorkChain wc : other.mChains) {
                     if (!mChains.contains(wc)) {
                         mChains.add(new WorkChain(wc));
+                        chainAdded = true;
                     }
                 }
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d22b62b..8093ff5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14306,18 +14306,17 @@
                 "backup_agent_timeout_parameters";
 
         /**
-         * Blacklist of GNSS satellites.
+         * Blocklist of GNSS satellites.
          *
          * This is a list of integers separated by commas to represent pairs of (constellation,
          * svid). Thus, the number of integers should be even.
          *
          * E.g.: "3,0,5,24" denotes (constellation=3, svid=0) and (constellation=5, svid=24) are
-         * blacklisted. Note that svid=0 denotes all svids in the
-         * constellation are blacklisted.
+         * blocklisted. Note that svid=0 denotes all svids in the constellation are blocklisted.
          *
          * @hide
          */
-        public static final String GNSS_SATELLITE_BLACKLIST = "gnss_satellite_blacklist";
+        public static final String GNSS_SATELLITE_BLOCKLIST = "gnss_satellite_blocklist";
 
         /**
          * Duration of updates in millisecond for GNSS location request from HAL to framework.
diff --git a/core/java/android/service/attestation/IImpressionAttestationService.aidl b/core/java/android/service/attestation/IImpressionAttestationService.aidl
new file mode 100644
index 0000000..8e858b8
--- /dev/null
+++ b/core/java/android/service/attestation/IImpressionAttestationService.aidl
@@ -0,0 +1,52 @@
+/*
+ * 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.service.attestation;
+
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.service.attestation.ImpressionToken;
+import android.os.RemoteCallback;
+
+/**
+ * Service used to handle impression attestation requests.
+ *
+ * @hide
+ */
+oneway interface IImpressionAttestationService {
+    /**
+     * Generates the impression token that can be used to validate that the system generated the
+     * token.
+     *
+     * @param screenshot The token for the window where the view is shown.
+     * @param bounds The size and position of the content being attested in the window.
+     * @param hashAlgorithm The String for the hashing algorithm to use based on values in
+     *        {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}.
+     * @param Callback The callback invoked to send back the impression token.
+     */
+    void generateImpressionToken(in HardwareBuffer screenshot, in Rect bounds,
+                                 in String hashAlgorithm, in RemoteCallback callback);
+
+    /**
+     * Call to verify that the impressionToken passed in was generated by the system. The result
+     * will be sent in the callback as an integer with the key {@link #EXTRA_VERIFICATION_STATUS}
+     * and will be one of the values in {@link VerificationStatus}.
+     *
+     * @param impressionToken The token to verify that it was generated by the system.
+     * @param callback The callback invoked to send back the verification status.
+     */
+    void verifyImpressionToken(in ImpressionToken impressionToken, in RemoteCallback callback);
+}
diff --git a/core/java/android/service/attestation/ImpressionAttestationService.java b/core/java/android/service/attestation/ImpressionAttestationService.java
new file mode 100644
index 0000000..4919f5d
--- /dev/null
+++ b/core/java/android/service/attestation/ImpressionAttestationService.java
@@ -0,0 +1,152 @@
+/*
+ * 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.service.attestation;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteCallback;
+
+/**
+ * A service that handles generating and verify ImpressionTokens.
+ *
+ * The service will generate an ImpressionToken based on arguments passed in. Then later that same
+ * ImpressionToken can be verified to determine that it was created by the system.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class ImpressionAttestationService extends Service {
+    /** @hide **/
+    public static final String EXTRA_IMPRESSION_TOKEN =
+            "android.service.attestation.extra.IMPRESSION_TOKEN";
+
+    /** @hide **/
+    public static final String EXTRA_VERIFICATION_STATUS =
+            "android.service.attestation.extra.VERIFICATION_STATUS";
+
+    /** @hide */
+    @IntDef(prefix = {"VERIFICATION_STATUS_"}, value = {
+            VERIFICATION_STATUS_UNKNOWN,
+            VERIFICATION_STATUS_OS_VERIFIED,
+            VERIFICATION_STATUS_APP_DECLARED
+    })
+    public @interface VerificationStatus {
+    }
+
+    public static final int VERIFICATION_STATUS_UNKNOWN = 0;
+    public static final int VERIFICATION_STATUS_OS_VERIFIED = 1;
+    public static final int VERIFICATION_STATUS_APP_DECLARED = 2;
+
+    /**
+     * Manifest metadata key for the resource string array containing the names of all impression
+     * attestation algorithms provided by the service.
+     * @hide
+     */
+    public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
+            "android.attestation.available_algorithms";
+
+    private ImpressionAttestationServiceWrapper mWrapper;
+    private Handler mHandler;
+
+    public ImpressionAttestationService() {
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mWrapper = new ImpressionAttestationServiceWrapper();
+        mHandler = new Handler(Looper.getMainLooper(), null, true);
+    }
+
+    @NonNull
+    @Override
+    public final IBinder onBind(@NonNull Intent intent) {
+        return mWrapper;
+    }
+
+    /**
+     * Generates the impression token that can be used to validate that the system
+     * generated the token.
+     *
+     * @param screenshot    The screenshot buffer for the content to attest.
+     * @param bounds        The size and position of the content being attested in the window.
+     * @param hashAlgorithm The String for the hashing algorithm to use based values in
+     *                      {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}.
+     * @return An impression token that can be used to validate information about the content.
+     * Returns null when the arguments sent are invalid.
+     */
+    @Nullable
+    public abstract ImpressionToken onGenerateImpressionToken(@NonNull HardwareBuffer screenshot,
+            @NonNull Rect bounds, @NonNull String hashAlgorithm);
+
+    /**
+     * Call to verify that the impressionToken passed in was generated by the system.
+     *
+     * @param impressionToken The token to verify that it was generated by the system.
+     * @return A {@link VerificationStatus} about whether the token was generated by the system.
+     */
+    public abstract @VerificationStatus int onVerifyImpressionToken(
+            @NonNull ImpressionToken impressionToken);
+
+    private void generateImpressionToken(HardwareBuffer screenshot, Rect bounds,
+            String hashAlgorithm, RemoteCallback callback) {
+        ImpressionToken impressionToken = onGenerateImpressionToken(screenshot, bounds,
+                hashAlgorithm);
+        final Bundle data = new Bundle();
+        data.putParcelable(EXTRA_IMPRESSION_TOKEN, impressionToken);
+        callback.sendResult(data);
+    }
+
+    private void verifyImpressionToken(ImpressionToken impressionToken,
+            RemoteCallback callback) {
+        @VerificationStatus int verificationStatus = onVerifyImpressionToken(impressionToken);
+        final Bundle data = new Bundle();
+        data.putInt(EXTRA_VERIFICATION_STATUS, verificationStatus);
+        callback.sendResult(data);
+    }
+
+    private final class ImpressionAttestationServiceWrapper extends
+            IImpressionAttestationService.Stub {
+        @Override
+        public void generateImpressionToken(HardwareBuffer screenshot, Rect bounds,
+                String hashAlgorithm, RemoteCallback callback) {
+            mHandler.sendMessage(
+                    obtainMessage(ImpressionAttestationService::generateImpressionToken,
+                            ImpressionAttestationService.this, screenshot, bounds, hashAlgorithm,
+                            callback));
+        }
+
+        @Override
+        public void verifyImpressionToken(ImpressionToken impressionToken,
+                RemoteCallback callback) {
+            mHandler.sendMessage(obtainMessage(ImpressionAttestationService::verifyImpressionToken,
+                    ImpressionAttestationService.this, impressionToken, callback));
+        }
+    }
+}
diff --git a/location/java/android/location/IBatchedLocationCallback.aidl b/core/java/android/service/attestation/ImpressionToken.aidl
similarity index 62%
copy from location/java/android/location/IBatchedLocationCallback.aidl
copy to core/java/android/service/attestation/ImpressionToken.aidl
index dce9f96..284a4ba 100644
--- a/location/java/android/location/IBatchedLocationCallback.aidl
+++ b/core/java/android/service/attestation/ImpressionToken.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2017, The Android Open Source Project
+ * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,16 +14,6 @@
  * limitations under the License.
  */
 
-package android.location;
+package android.service.attestation;
 
-import android.location.Location;
-
-import java.util.List;
-
-/**
- * {@hide}
- */
-oneway interface IBatchedLocationCallback
-{
-    void onLocationBatch(in List<Location> locations);
-}
+parcelable ImpressionToken;
\ No newline at end of file
diff --git a/core/java/android/service/attestation/ImpressionToken.java b/core/java/android/service/attestation/ImpressionToken.java
new file mode 100644
index 0000000..4355dc0
--- /dev/null
+++ b/core/java/android/service/attestation/ImpressionToken.java
@@ -0,0 +1,250 @@
+/*
+ * 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.service.attestation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * The ads impression token used to validate information about what was present on screen.
+ * @hide
+ *
+ * TODO: Remove hide and SystemAPI since this will be a public class
+ */
+@SystemApi
+@DataClass(genToString = true, genAidl = true)
+public final class ImpressionToken implements Parcelable {
+    /**
+     * The timestamp when the screenshot was generated.
+     */
+    private final long mScreenshotTimeMillis;
+
+    /**
+     * The bounds of the requested area to take the screenshot. This is in window space passed in
+     * by the client.
+     */
+    private @NonNull final Rect mBoundsInWindow;
+
+    /**
+     * The selected hashing algorithm that generated the image hash.
+     */
+    private @NonNull final String mHashingAlgorithm;
+
+    /**
+     * The image hash generated when creating the impression token from the screenshot taken.
+     */
+    private @NonNull final byte[] mImageHash;
+
+    /**
+     * The hmac generated by the system and used to verify whether this token was generated by
+     * the system. This should only be accessed by a system process.
+     */
+    private @NonNull final byte[] mHmac;
+
+    /**
+     * The hmac generated by the system and used to verify whether this token was generated by
+     * the system. This should only be accessed by a system process.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull byte[] getHmac() {
+        return mHmac;
+    }
+
+
+
+    // Code below generated by codegen v1.0.18.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/attestation/ImpressionToken.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new ImpressionToken.
+     *
+     * @param screenshotTimeMillis
+     *   The timestamp when the screenshot was generated.
+     * @param boundsInWindow
+     *   The bounds of the requested area to take the screenshot. This is in window space passed in
+     *   by the client.
+     * @param hashingAlgorithm
+     *   The selected hashing algorithm that generated the image hash.
+     * @param imageHash
+     *   The image hash generated when creating the impression token from the screenshot taken.
+     * @param hmac
+     *   The hmac generated by the system and used to verify whether this token was generated by
+     *   the system. This should only be accessed by a system process.
+     */
+    @DataClass.Generated.Member
+    public ImpressionToken(
+            long screenshotTimeMillis,
+            @NonNull Rect boundsInWindow,
+            @NonNull String hashingAlgorithm,
+            @NonNull byte[] imageHash,
+            @NonNull byte[] hmac) {
+        this.mScreenshotTimeMillis = screenshotTimeMillis;
+        this.mBoundsInWindow = boundsInWindow;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mBoundsInWindow);
+        this.mHashingAlgorithm = hashingAlgorithm;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHashingAlgorithm);
+        this.mImageHash = imageHash;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mImageHash);
+        this.mHmac = hmac;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHmac);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The timestamp when the screenshot was generated.
+     */
+    @DataClass.Generated.Member
+    public long getScreenshotTimeMillis() {
+        return mScreenshotTimeMillis;
+    }
+
+    /**
+     * The bounds of the requested area to take the screenshot. This is in window space passed in
+     * by the client.
+     */
+    @DataClass.Generated.Member
+    public @NonNull Rect getBoundsInWindow() {
+        return mBoundsInWindow;
+    }
+
+    /**
+     * The selected hashing algorithm that generated the image hash.
+     */
+    @DataClass.Generated.Member
+    public @NonNull String getHashingAlgorithm() {
+        return mHashingAlgorithm;
+    }
+
+    /**
+     * The image hash generated when creating the impression token from the screenshot taken.
+     */
+    @DataClass.Generated.Member
+    public @NonNull byte[] getImageHash() {
+        return mImageHash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ImpressionToken { " +
+                "screenshotTimeMillis = " + mScreenshotTimeMillis + ", " +
+                "boundsInWindow = " + mBoundsInWindow + ", " +
+                "hashingAlgorithm = " + mHashingAlgorithm + ", " +
+                "imageHash = " + java.util.Arrays.toString(mImageHash) + ", " +
+                "hmac = " + java.util.Arrays.toString(mHmac) +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeLong(mScreenshotTimeMillis);
+        dest.writeTypedObject(mBoundsInWindow, flags);
+        dest.writeString(mHashingAlgorithm);
+        dest.writeByteArray(mImageHash);
+        dest.writeByteArray(mHmac);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ImpressionToken(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        long screenshotTimeMillis = in.readLong();
+        Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR);
+        String hashingAlgorithm = in.readString();
+        byte[] imageHash = in.createByteArray();
+        byte[] hmac = in.createByteArray();
+
+        this.mScreenshotTimeMillis = screenshotTimeMillis;
+        this.mBoundsInWindow = boundsInWindow;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mBoundsInWindow);
+        this.mHashingAlgorithm = hashingAlgorithm;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHashingAlgorithm);
+        this.mImageHash = imageHash;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mImageHash);
+        this.mHmac = hmac;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHmac);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ImpressionToken> CREATOR
+            = new Parcelable.Creator<ImpressionToken>() {
+        @Override
+        public ImpressionToken[] newArray(int size) {
+            return new ImpressionToken[size];
+        }
+
+        @Override
+        public ImpressionToken createFromParcel(@NonNull Parcel in) {
+            return new ImpressionToken(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1604539951959L,
+            codegenVersion = "1.0.18",
+            sourceFile = "frameworks/base/core/java/android/service/attestation/ImpressionToken.java",
+            inputSignatures = "private final  long mScreenshotTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashingAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate final @android.annotation.NonNull byte[] mHmac\npublic @android.annotation.SystemApi @android.annotation.NonNull byte[] getHmac()\nclass ImpressionToken extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 8e6c26a..84c209b 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.icu.text.DateFormatSymbols;
@@ -170,7 +170,7 @@
      * mean using 12-hour in some locales and, in this case, is duplicated as the 'a' field.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
     static final long DISALLOW_DUPLICATE_FIELD_IN_SKELETON = 170233598L;
 
     /**
diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java
new file mode 100644
index 0000000..80c2055
--- /dev/null
+++ b/core/java/android/util/CharsetUtils.java
@@ -0,0 +1,64 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * Specializations of {@code libcore.util.CharsetUtils} which enable efficient
+ * in-place encoding without making any new allocations.
+ * <p>
+ * These methods purposefully accept only non-movable byte array addresses to
+ * avoid extra JNI overhead.
+ *
+ * @hide
+ */
+public class CharsetUtils {
+    /**
+     * Attempt to encode the given string as UTF-8 into the destination byte
+     * array without making any new allocations.
+     *
+     * @param src string value to be encoded
+     * @param dest destination byte array to encode into
+     * @param destOff offset into destination where encoding should begin
+     * @param destLen length of destination
+     * @return the number of bytes written to the destination when encoded
+     *         successfully, otherwise {@code -1} if not large enough
+     */
+    public static int toUtf8Bytes(@NonNull String src,
+            long dest, int destOff, int destLen) {
+        return toUtf8Bytes(src, src.length(), dest, destOff, destLen);
+    }
+
+    /**
+     * Attempt to encode the given string as UTF-8 into the destination byte
+     * array without making any new allocations.
+     *
+     * @param src string value to be encoded
+     * @param srcLen exact length of string to be encoded
+     * @param dest destination byte array to encode into
+     * @param destOff offset into destination where encoding should begin
+     * @param destLen length of destination
+     * @return the number of bytes written to the destination when encoded
+     *         successfully, otherwise {@code -1} if not large enough
+     */
+    @FastNative
+    private static native int toUtf8Bytes(@NonNull String src, int srcLen,
+            long dest, int destOff, int destLen);
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c20b063..a5ca9ef 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -23,7 +23,9 @@
 import android.text.TextUtils;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Util class to get feature flag information.
@@ -70,6 +72,12 @@
         DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
     }
 
+    private static final Set<String> PERSISTENT_FLAGS;
+    static {
+        PERSISTENT_FLAGS = new HashSet<>();
+        PERSISTENT_FLAGS.add(SETTINGS_PROVIDER_MODEL);
+    }
+
     /**
      * Whether or not a flag is enabled.
      *
@@ -89,8 +97,9 @@
             }
         }
 
-        // Step 2: check if feature flag has any override. Flag name: sys.fflag.override.<feature>
-        value = SystemProperties.get(FFLAG_OVERRIDE_PREFIX + feature);
+        // Step 2: check if feature flag has any override.
+        // Flag name: [persist.]sys.fflag.override.<feature>
+        value = SystemProperties.get(getSystemPropertyPrefix(feature) + feature);
         if (!TextUtils.isEmpty(value)) {
             return Boolean.parseBoolean(value);
         }
@@ -103,7 +112,8 @@
      * Override feature flag to new state.
      */
     public static void setEnabled(Context context, String feature, boolean enabled) {
-        SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+        SystemProperties.set(getSystemPropertyPrefix(feature) + feature,
+                enabled ? "true" : "false");
     }
 
     /**
@@ -112,4 +122,8 @@
     public static Map<String, String> getAllFeatureFlags() {
         return DEFAULT_FLAGS;
     }
+
+    private static String getSystemPropertyPrefix(String feature) {
+        return PERSISTENT_FLAGS.contains(feature) ? PERSIST_PREFIX : FFLAG_OVERRIDE_PREFIX;
+    }
 }
diff --git a/core/java/android/util/TypedXmlPullParser.java b/core/java/android/util/TypedXmlPullParser.java
new file mode 100644
index 0000000..5ff7e5d
--- /dev/null
+++ b/core/java/android/util/TypedXmlPullParser.java
@@ -0,0 +1,186 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.IOException;
+
+/**
+ * Specialization of {@link XmlPullParser} which adds explicit methods to
+ * support consistent and efficient conversion of primitive data types.
+ *
+ * @hide
+ */
+public interface TypedXmlPullParser extends XmlPullParser {
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, or
+     *         {@code null} if malformed or undefined
+     */
+    @Nullable byte[] getAttributeBytesHex(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, or
+     *         {@code null} if malformed or undefined
+     */
+    @Nullable byte[] getAttributeBytesBase64(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    int getAttributeInt(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    int getAttributeIntHex(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    long getAttributeLong(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    long getAttributeLongHex(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    float getAttributeFloat(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    double getAttributeDouble(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}
+     * @throws IOException if the value is malformed or undefined
+     */
+    boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name)
+            throws IOException;
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default int getAttributeInt(@Nullable String namespace, @NonNull String name,
+            int defaultValue) {
+        try {
+            return getAttributeInt(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default int getAttributeIntHex(@Nullable String namespace, @NonNull String name,
+            int defaultValue) {
+        try {
+            return getAttributeIntHex(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default long getAttributeLong(@Nullable String namespace, @NonNull String name,
+            long defaultValue) {
+        try {
+            return getAttributeLong(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default long getAttributeLongHex(@Nullable String namespace, @NonNull String name,
+            long defaultValue) {
+        try {
+            return getAttributeLongHex(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default float getAttributeFloat(@Nullable String namespace, @NonNull String name,
+            float defaultValue) {
+        try {
+            return getAttributeFloat(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default double getAttributeDouble(@Nullable String namespace, @NonNull String name,
+            double defaultValue) {
+        try {
+            return getAttributeDouble(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+     *         default value if the value is malformed or undefined
+     */
+    default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name,
+            boolean defaultValue) {
+        try {
+            return getAttributeBoolean(namespace, name);
+        } catch (Exception ignored) {
+            return defaultValue;
+        }
+    }
+}
diff --git a/core/java/android/util/TypedXmlSerializer.java b/core/java/android/util/TypedXmlSerializer.java
new file mode 100644
index 0000000..fe5e3e6
--- /dev/null
+++ b/core/java/android/util/TypedXmlSerializer.java
@@ -0,0 +1,103 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+/**
+ * Specialization of {@link XmlSerializer} which adds explicit methods to
+ * support consistent and efficient conversion of primitive data types.
+ *
+ * @hide
+ */
+public interface TypedXmlSerializer extends XmlSerializer {
+    /**
+     * Functionally equivalent to {@link #attribute(String, String, String)} but
+     * with the additional signal that the given value is a candidate for being
+     * canonicalized, similar to {@link String#intern()}.
+     */
+    @NonNull XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name,
+            @Nullable String value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name,
+            byte[] value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name,
+            byte[] value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name,
+            int value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name,
+            int value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name,
+            long value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name,
+            long value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name,
+            float value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name,
+            double value) throws IOException;
+
+    /**
+     * Encode the given strongly-typed value and serialize using
+     * {@link #attribute(String, String, String)}.
+     */
+    @NonNull XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name,
+            boolean value) throws IOException;
+}
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index e3b8fec..cc6ed2e 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -16,6 +16,14 @@
 
 package android.util;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.BinaryXmlPullParser;
+import com.android.internal.util.BinaryXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
 import libcore.util.XmlObjectFactory;
 
 import org.xml.sax.ContentHandler;
@@ -26,11 +34,15 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * XML utility methods.
@@ -99,6 +111,57 @@
     }
 
     /**
+     * Creates a new {@link TypedXmlPullParser} which is optimized for use
+     * inside the system, typically by supporting only a basic set of features.
+     * <p>
+     * In particular, the returned parser does not support namespaces, prefixes,
+     * properties, or options.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlPullParser newFastPullParser() {
+        return XmlUtils.makeTyped(newPullParser());
+    }
+
+    /**
+     * Creates a new {@link XmlPullParser} that reads XML documents using a
+     * custom binary wire protocol which benchmarking has shown to be 8.5x
+     * faster than {@code Xml.newFastPullParser()} for a typical
+     * {@code packages.xml}.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlPullParser newBinaryPullParser() {
+        return new BinaryXmlPullParser();
+    }
+
+    /**
+     * Creates a new {@link XmlPullParser} which is optimized for use inside the
+     * system, typically by supporting only a basic set of features.
+     * <p>
+     * This returned instance may be configured to read using an efficient
+     * binary format instead of a human-readable text format, depending on
+     * device feature flags.
+     * <p>
+     * To ensure that both formats are detected and transparently handled
+     * correctly, you must shift to using both {@link #resolveSerializer} and
+     * {@link #resolvePullParser}.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
+            throws IOException {
+        // TODO: add support for binary format
+        final TypedXmlPullParser xml = newFastPullParser();
+        try {
+            xml.setInput(in, StandardCharsets.UTF_8.name());
+        } catch (XmlPullParserException e) {
+            throw new IOException(e);
+        }
+        return xml;
+    }
+
+    /**
      * Creates a new xml serializer.
      */
     public static XmlSerializer newSerializer() {
@@ -106,6 +169,129 @@
     }
 
     /**
+     * Creates a new {@link XmlSerializer} which is optimized for use inside the
+     * system, typically by supporting only a basic set of features.
+     * <p>
+     * In particular, the returned parser does not support namespaces, prefixes,
+     * properties, or options.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlSerializer newFastSerializer() {
+        return XmlUtils.makeTyped(new FastXmlSerializer());
+    }
+
+    /**
+     * Creates a new {@link XmlSerializer} that writes XML documents using a
+     * custom binary wire protocol which benchmarking has shown to be 4.4x
+     * faster and use 2.8x less disk space than {@code Xml.newFastSerializer()}
+     * for a typical {@code packages.xml}.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlSerializer newBinarySerializer() {
+        return new BinaryXmlSerializer();
+    }
+
+    /**
+     * Creates a new {@link XmlSerializer} which is optimized for use inside the
+     * system, typically by supporting only a basic set of features.
+     * <p>
+     * This returned instance may be configured to write using an efficient
+     * binary format instead of a human-readable text format, depending on
+     * device feature flags.
+     * <p>
+     * To ensure that both formats are detected and transparently handled
+     * correctly, you must shift to using both {@link #resolveSerializer} and
+     * {@link #resolvePullParser}.
+     *
+     * @hide
+     */
+    public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)
+            throws IOException {
+        // TODO: add support for binary format
+        final TypedXmlSerializer xml = newFastSerializer();
+        xml.setOutput(out, StandardCharsets.UTF_8.name());
+        return xml;
+    }
+
+    /**
+     * Copy the first XML document into the second document.
+     * <p>
+     * Implemented by reading all events from the given {@link XmlPullParser}
+     * and writing them directly to the given {@link XmlSerializer}. This can be
+     * useful for transparently converting between underlying wire protocols.
+     *
+     * @hide
+     */
+    public static void copy(@NonNull XmlPullParser in, @NonNull XmlSerializer out)
+            throws XmlPullParserException, IOException {
+        // Some parsers may have already consumed the event that starts the
+        // document, so we manually emit that event here for consistency
+        if (in.getEventType() == XmlPullParser.START_DOCUMENT) {
+            out.startDocument(in.getInputEncoding(), true);
+        }
+
+        while (true) {
+            final int token = in.nextToken();
+            switch (token) {
+                case XmlPullParser.START_DOCUMENT:
+                    out.startDocument(in.getInputEncoding(), true);
+                    break;
+                case XmlPullParser.END_DOCUMENT:
+                    out.endDocument();
+                    return;
+                case XmlPullParser.START_TAG:
+                    out.startTag(normalizeNamespace(in.getNamespace()), in.getName());
+                    for (int i = 0; i < in.getAttributeCount(); i++) {
+                        out.attribute(normalizeNamespace(in.getAttributeNamespace(i)),
+                                in.getAttributeName(i), in.getAttributeValue(i));
+                    }
+                    break;
+                case XmlPullParser.END_TAG:
+                    out.endTag(normalizeNamespace(in.getNamespace()), in.getName());
+                    break;
+                case XmlPullParser.TEXT:
+                    out.text(in.getText());
+                    break;
+                case XmlPullParser.CDSECT:
+                    out.cdsect(in.getText());
+                    break;
+                case XmlPullParser.ENTITY_REF:
+                    out.entityRef(in.getName());
+                    break;
+                case XmlPullParser.IGNORABLE_WHITESPACE:
+                    out.ignorableWhitespace(in.getText());
+                    break;
+                case XmlPullParser.PROCESSING_INSTRUCTION:
+                    out.processingInstruction(in.getText());
+                    break;
+                case XmlPullParser.COMMENT:
+                    out.comment(in.getText());
+                    break;
+                case XmlPullParser.DOCDECL:
+                    out.docdecl(in.getText());
+                    break;
+                default:
+                    throw new IllegalStateException("Unknown token " + token);
+            }
+        }
+    }
+
+    /**
+     * Some parsers may return an empty string {@code ""} when a namespace in
+     * unsupported, which can confuse serializers. This method normalizes empty
+     * strings to be {@code null}.
+     */
+    private static @Nullable String normalizeNamespace(@Nullable String namespace) {
+        if (namespace == null || namespace.isEmpty()) {
+            return null;
+        } else {
+            return namespace;
+        }
+    }
+
+    /**
      * Supported character encodings.
      */
     public enum Encoding {
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index d58d5bf..6bf7d6f 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -176,15 +176,14 @@
      * arrangement, a platform may only support hemi-spherical azimuth angles
      * ranging from -pi/2 to pi/2
      */
-    public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 2;
+    public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3;
 
     /**
      * Indicate support for three dimensional angle of arrival measurement.
      * Typically requires at least three antennas. This mode supports full
      * azimuth angles ranging from -pi to pi.
      */
-    public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 3;
-
+    public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4;
 
     /**
      * Gets the {@link AngleOfArrivalSupportType} supported on this platform
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 237ed72..3021aa6a 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1405,16 +1405,29 @@
         private final int mWidth;
         private final int mHeight;
         private final float mRefreshRate;
+        @NonNull
+        private final float[] mAlternativeRefreshRates;
 
         /**
          * @hide
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public Mode(int modeId, int width, int height, float refreshRate) {
+            this(modeId, width, height, refreshRate, new float[0]);
+        }
+
+        /**
+         * @hide
+         */
+        public Mode(int modeId, int width, int height, float refreshRate,
+                float[] alternativeRefreshRates) {
             mModeId = modeId;
             mWidth = width;
             mHeight = height;
             mRefreshRate = refreshRate;
+            mAlternativeRefreshRates =
+                    Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
+            Arrays.sort(mAlternativeRefreshRates);
         }
 
         /**
@@ -1464,6 +1477,28 @@
         }
 
         /**
+         * Returns an array of refresh rates which can be switched to seamlessly.
+         * <p>
+         * A seamless switch is one without visual interruptions, such as a black screen for
+         * a second or two.
+         * <p>
+         * Presence in this list does not guarantee a switch will occur to the desired
+         * refresh rate, but rather, if a switch does occur to a refresh rate in this list,
+         * it is guaranteed to be seamless.
+         * <p>
+         * The binary relation "refresh rate X is alternative to Y" is non-reflexive,
+         * symmetric and transitive. For example the mode 1920x1080 60Hz, will never have an
+         * alternative refresh rate of 60Hz. If 1920x1080 60Hz has an alternative of 50Hz
+         * then 1920x1080 50Hz will have alternative refresh rate of 60Hz. If 1920x1080 60Hz
+         * has an alternative of 50Hz and 1920x1080 50Hz has an alternative of 24Hz, then 1920x1080
+         * 60Hz will also have an alternative of 24Hz.
+         */
+        @NonNull
+        public float[] getAlternativeRefreshRates() {
+            return mAlternativeRefreshRates;
+        }
+
+        /**
          * Returns {@code true} if this mode matches the given parameters.
          *
          * @hide
@@ -1483,7 +1518,8 @@
                 return false;
             }
             Mode that = (Mode) other;
-            return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate);
+            return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate)
+                    && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates);
         }
 
         @Override
@@ -1493,6 +1529,7 @@
             hash = hash * 17 + mWidth;
             hash = hash * 17 + mHeight;
             hash = hash * 17 + Float.floatToIntBits(mRefreshRate);
+            hash = hash * 17 + Arrays.hashCode(mAlternativeRefreshRates);
             return hash;
         }
 
@@ -1503,6 +1540,8 @@
                     .append(", width=").append(mWidth)
                     .append(", height=").append(mHeight)
                     .append(", fps=").append(mRefreshRate)
+                    .append(", alternativeRefreshRates=")
+                    .append(Arrays.toString(mAlternativeRefreshRates))
                     .append("}")
                     .toString();
         }
@@ -1513,7 +1552,7 @@
         }
 
         private Mode(Parcel in) {
-            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat());
+            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray());
         }
 
         @Override
@@ -1522,6 +1561,7 @@
             out.writeInt(mWidth);
             out.writeInt(mHeight);
             out.writeFloat(mRefreshRate);
+            out.writeFloatArray(mAlternativeRefreshRates);
         }
 
         @SuppressWarnings("hiding")
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 16211fc..c2f17c3 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -604,7 +604,6 @@
     /**
      * @return the duration in milliseconds between the first tap's up event and the second tap's
      * down event for an interaction to be considered part of the same multi-press.
-     * @hide
      */
     public static int getMultiPressTimeout() {
         return AppGlobals.getIntCoreSetting(Settings.Secure.MULTI_PRESS_TIMEOUT,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9d24dff1..c077006 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2643,18 +2643,12 @@
                 || mForceNextWindowRelayout) {
             mForceNextWindowRelayout = false;
 
-            if (isViewVisible) {
-                // If this window is giving internal insets to the window
-                // manager, and it is being added or changing its visibility,
-                // then we want to first give the window manager "fake"
-                // insets to cause it to effectively ignore the content of
-                // the window during layout.  This avoids it briefly causing
-                // other windows to resize/move based on the raw frame of the
-                // window, waiting until we can finish laying out this window
-                // and get back to the window manager with the ultimately
-                // computed insets.
-                insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
-            }
+            // If this window is giving internal insets to the window manager, then we want to first
+            // make the provided insets unchanged during layout. This avoids it briefly causing
+            // other windows to resize/move based on the raw frame of the window, waiting until we
+            // can finish laying out this window and get back to the window manager with the
+            // ultimately computed insets.
+            insetsPending = computesInternalInsets;
 
             if (mSurfaceHolder != null) {
                 mSurfaceHolder.mSurfaceLock.lock();
@@ -3912,7 +3906,8 @@
             return;
         }
 
-        final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw;
+        final boolean fullRedrawNeeded =
+                mFullRedrawNeeded || mReportNextDraw || mNextDrawUseBLASTSyncTransaction;
         mFullRedrawNeeded = false;
 
         mIsDrawing = true;
@@ -9921,6 +9916,18 @@
             } else {
                 t.merge(mRtBLASTSyncTransaction);
             }
+
+            // There's potential for the frame callback to get called even if nothing was drawn.
+            // When that occurs, we remove the transaction sent to BBQ since the draw we were
+            // waiting on will not happen. We can apply the transaction here but it will not contain
+            // a buffer since nothing new was drawn.
+            //
+            // This is mainly for the case when the SurfaceView has changed and wants to synchronize
+            // with the main window. If the main window doesn't need to draw anything, we can just
+            // apply the transaction without the new buffer from the main window.
+            if (mBlastBufferQueue != null) {
+                mBlastBufferQueue.setNextTransaction(null);
+            }
         }
     }
 
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 92e9a96..a5be202 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -462,7 +462,7 @@
 
         /**
          * Creates a new set of layout parameters with the specified width, height
-         * and weight.
+         * and gravity.
          *
          * @param width the width, either {@link #MATCH_PARENT},
          *              {@link #WRAP_CONTENT} or a fixed size in pixels
diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java
index 15463cb..9049ca5 100644
--- a/core/java/com/android/internal/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/BrightnessSynchronizer.java
@@ -73,18 +73,26 @@
         }
     };
 
-    public BrightnessSynchronizer(Context context) {
-        final BrightnessSyncObserver mBrightnessSyncObserver;
-        mContext = context;
-        mBrightnessSyncObserver = new BrightnessSyncObserver(mHandler);
-        mBrightnessSyncObserver.startObserving();
+    private float mPreferredSettingValue;
 
-        // 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);
+    public BrightnessSynchronizer(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Starts brightnessSyncObserver to ensure that the float and int brightness values stay
+     * in sync.
+     * This also ensures that values are synchronized at system start up too.
+     * 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.
+     */
+    public void startSynchronizing() {
+        final BrightnessSyncObserver brightnessSyncObserver;
+        brightnessSyncObserver = new BrightnessSyncObserver(mHandler);
+        brightnessSyncObserver.startObserving();
+
+        final float currentFloatBrightness = getScreenBrightnessFloat(mContext);
+        final int currentIntBrightness = getScreenBrightnessInt(mContext);
 
         if (!Float.isNaN(currentFloatBrightness)) {
             updateBrightnessIntFromFloat(currentFloatBrightness);
@@ -156,8 +164,6 @@
                 UserHandle.USER_CURRENT);
     }
 
-    private float mPreferredSettingValue;
-
     /**
      * Updates the float setting based on a passed in int value. This is called whenever the int
      * setting changes. mWriteHistory keeps a record of the values that been written to the settings
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
index 1a93f1b..3e26679 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -33,7 +33,7 @@
      */
     public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS =
             DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, false);
+                SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, true);
 
     /**
      * Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 5571a58..e067f5f 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -776,8 +776,10 @@
 
         int matchesCount = 0;
         int size = size(items);
+        final boolean[] tests = new boolean[size];
         for (int i = 0; i < size; i++) {
-            if (predicate.test(items[i])) {
+            tests[i] = predicate.test(items[i]);
+            if (tests[i]) {
                 matchesCount++;
             }
         }
@@ -790,7 +792,7 @@
         }
         int outIdx = 0;
         for (int i = 0; i < size; i++) {
-            if (predicate.test(items[i])) {
+            if (tests[i]) {
                 result[outIdx++] = items[i];
             }
         }
diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java
new file mode 100644
index 0000000..da16eca
--- /dev/null
+++ b/core/java/com/android/internal/util/BinaryXmlPullParser.java
@@ -0,0 +1,899 @@
+/*
+ * 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.internal.util;
+
+import static com.android.internal.util.BinaryXmlSerializer.ATTRIBUTE;
+import static com.android.internal.util.BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_FALSE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_TRUE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_BASE64;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_DOUBLE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_FLOAT;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_NULL;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING_INTERNED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Parser that reads XML documents using a custom binary wire protocol which
+ * benchmarking has shown to be 8.5x faster than {@link Xml.newFastPullParser()}
+ * for a typical {@code packages.xml}.
+ * <p>
+ * The high-level design of the wire protocol is to directly serialize the event
+ * stream, while efficiently and compactly writing strongly-typed primitives
+ * delivered through the {@link TypedXmlSerializer} interface.
+ * <p>
+ * Each serialized event is a single byte where the lower half is a normal
+ * {@link XmlPullParser} token and the upper half is an optional data type
+ * signal, such as {@link #TYPE_INT}.
+ * <p>
+ * This parser has some specific limitations:
+ * <ul>
+ * <li>Only the UTF-8 encoding is supported.
+ * <li>Variable length values, such as {@code byte[]} or {@link String}, are
+ * limited to 65,535 bytes in length. Note that {@link String} values are stored
+ * as UTF-8 on the wire.
+ * <li>Namespaces, prefixes, properties, and options are unsupported.
+ * </ul>
+ */
+public final class BinaryXmlPullParser implements TypedXmlPullParser {
+    /**
+     * Default buffer size, which matches {@code FastXmlSerializer}. This should
+     * be kept in sync with {@link BinaryXmlPullParser}.
+     */
+    private static final int BUFFER_SIZE = 32_768;
+
+    private FastDataInput mIn;
+
+    private int mCurrentToken = START_DOCUMENT;
+    private int mCurrentDepth = 0;
+    private String mCurrentName;
+    private String mCurrentText;
+
+    /**
+     * Pool of attributes parsed for the currently tag. All interactions should
+     * be done via {@link #obtainAttribute()}, {@link #findAttribute(String)},
+     * and {@link #resetAttributes()}.
+     */
+    private int mAttributeCount = 0;
+    private Attribute[] mAttributes;
+
+    @Override
+    public void setInput(InputStream is, String inputEncoding) throws XmlPullParserException {
+        if (inputEncoding != null && !StandardCharsets.UTF_8.name().equals(inputEncoding)) {
+            throw new UnsupportedOperationException();
+        }
+
+        mIn = new FastDataInput(is, BUFFER_SIZE);
+
+        mCurrentToken = START_DOCUMENT;
+        mCurrentDepth = 0;
+        mCurrentName = null;
+        mCurrentText = null;
+
+        mAttributeCount = 0;
+        mAttributes = new Attribute[8];
+        for (int i = 0; i < mAttributes.length; i++) {
+            mAttributes[i] = new Attribute();
+        }
+
+        try {
+            final byte[] magic = new byte[4];
+            mIn.readFully(magic);
+            if (!Arrays.equals(magic, PROTOCOL_MAGIC_VERSION_0)) {
+                throw new IOException("Unexpected magic " + bytesToHexString(magic));
+            }
+
+            // We're willing to immediately consume a START_DOCUMENT if present,
+            // but we're okay if it's missing
+            if (peekNextExternalToken() == START_DOCUMENT) {
+                consumeToken();
+            }
+        } catch (IOException e) {
+            throw new XmlPullParserException(e.toString());
+        }
+    }
+
+    @Override
+    public void setInput(Reader in) throws XmlPullParserException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int next() throws XmlPullParserException, IOException {
+        while (true) {
+            final int token = nextToken();
+            switch (token) {
+                case START_TAG:
+                case END_TAG:
+                case END_DOCUMENT:
+                    return token;
+                case TEXT:
+                    consumeAdditionalText();
+                    // Per interface docs, empty text regions are skipped
+                    if (mCurrentText == null || mCurrentText.length() == 0) {
+                        continue;
+                    } else {
+                        return TEXT;
+                    }
+            }
+        }
+    }
+
+    @Override
+    public int nextToken() throws XmlPullParserException, IOException {
+        if (mCurrentToken == XmlPullParser.END_TAG) {
+            mCurrentDepth--;
+        }
+
+        int token;
+        try {
+            token = peekNextExternalToken();
+            consumeToken();
+        } catch (EOFException e) {
+            token = END_DOCUMENT;
+        }
+        switch (token) {
+            case XmlPullParser.START_TAG:
+                // We need to peek forward to find the next external token so
+                // that we parse all pending INTERNAL_ATTRIBUTE tokens
+                peekNextExternalToken();
+                mCurrentDepth++;
+                break;
+        }
+        mCurrentToken = token;
+        return token;
+    }
+
+    /**
+     * Peek at the next "external" token without consuming it.
+     * <p>
+     * External tokens, such as {@link #START_TAG}, are expected by typical
+     * {@link XmlPullParser} clients. In contrast, internal tokens, such as
+     * {@link #ATTRIBUTE}, are not expected by typical clients.
+     * <p>
+     * This method consumes any internal events until it reaches the next
+     * external event.
+     */
+    private int peekNextExternalToken() throws IOException, XmlPullParserException {
+        while (true) {
+            final int token = peekNextToken();
+            switch (token) {
+                case ATTRIBUTE:
+                    consumeToken();
+                    continue;
+                default:
+                    return token;
+            }
+        }
+    }
+
+    /**
+     * Peek at the next token in the underlying stream without consuming it.
+     */
+    private int peekNextToken() throws IOException {
+        return mIn.peekByte() & 0x0f;
+    }
+
+    /**
+     * Parse and consume the next token in the underlying stream.
+     */
+    private void consumeToken() throws IOException, XmlPullParserException {
+        final int event = mIn.readByte();
+        final int token = event & 0x0f;
+        final int type = event & 0xf0;
+        switch (token) {
+            case ATTRIBUTE: {
+                final Attribute attr = obtainAttribute();
+                attr.name = mIn.readInternedUTF();
+                attr.type = type;
+                switch (type) {
+                    case TYPE_NULL:
+                    case TYPE_BOOLEAN_TRUE:
+                    case TYPE_BOOLEAN_FALSE:
+                        // Nothing extra to fill in
+                        break;
+                    case TYPE_STRING:
+                        attr.valueString = mIn.readUTF();
+                        break;
+                    case TYPE_STRING_INTERNED:
+                        attr.valueString = mIn.readInternedUTF();
+                        break;
+                    case TYPE_BYTES_HEX:
+                    case TYPE_BYTES_BASE64:
+                        final int len = mIn.readUnsignedShort();
+                        final byte[] res = new byte[len];
+                        mIn.readFully(res);
+                        attr.valueBytes = res;
+                        break;
+                    case TYPE_INT:
+                    case TYPE_INT_HEX:
+                        attr.valueInt = mIn.readInt();
+                        break;
+                    case TYPE_LONG:
+                    case TYPE_LONG_HEX:
+                        attr.valueLong = mIn.readLong();
+                        break;
+                    case TYPE_FLOAT:
+                        attr.valueFloat = mIn.readFloat();
+                        break;
+                    case TYPE_DOUBLE:
+                        attr.valueDouble = mIn.readDouble();
+                        break;
+                    default:
+                        throw new IOException("Unexpected data type " + type);
+                }
+                break;
+            }
+            case XmlPullParser.START_DOCUMENT: {
+                break;
+            }
+            case XmlPullParser.END_DOCUMENT: {
+                break;
+            }
+            case XmlPullParser.START_TAG: {
+                mCurrentName = mIn.readInternedUTF();
+                resetAttributes();
+                break;
+            }
+            case XmlPullParser.END_TAG: {
+                mCurrentName = mIn.readInternedUTF();
+                resetAttributes();
+                break;
+            }
+            case XmlPullParser.TEXT:
+            case XmlPullParser.CDSECT:
+            case XmlPullParser.PROCESSING_INSTRUCTION:
+            case XmlPullParser.COMMENT:
+            case XmlPullParser.DOCDECL:
+            case XmlPullParser.IGNORABLE_WHITESPACE: {
+                mCurrentText = mIn.readUTF();
+                break;
+            }
+            case XmlPullParser.ENTITY_REF: {
+                mCurrentName = mIn.readUTF();
+                mCurrentText = resolveEntity(mCurrentName);
+                break;
+            }
+            default: {
+                throw new IOException("Unknown token " + token + " with type " + type);
+            }
+        }
+    }
+
+    /**
+     * When the current tag is {@link #TEXT}, consume all subsequent "text"
+     * events, as described by {@link #next}. When finished, the current event
+     * will still be {@link #TEXT}.
+     */
+    private void consumeAdditionalText() throws IOException, XmlPullParserException {
+        String combinedText = mCurrentText;
+        while (true) {
+            final int token = peekNextExternalToken();
+            switch (token) {
+                case COMMENT:
+                case PROCESSING_INSTRUCTION:
+                    // Quietly consumed
+                    consumeToken();
+                    break;
+                case TEXT:
+                case CDSECT:
+                case ENTITY_REF:
+                    // Additional text regions collected
+                    consumeToken();
+                    combinedText += mCurrentText;
+                    break;
+                default:
+                    // Next token is something non-text, so wrap things up
+                    mCurrentToken = TEXT;
+                    mCurrentName = null;
+                    mCurrentText = combinedText;
+                    return;
+            }
+        }
+    }
+
+    static @NonNull String resolveEntity(@NonNull String entity)
+            throws XmlPullParserException {
+        switch (entity) {
+            case "lt": return "<";
+            case "gt": return ">";
+            case "amp": return "&";
+            case "apos": return "'";
+            case "quot": return "\"";
+        }
+        if (entity.length() > 1 && entity.charAt(0) == '#') {
+            final char c = (char) Integer.parseInt(entity.substring(1));
+            return new String(new char[] { c });
+        }
+        throw new XmlPullParserException("Unknown entity " + entity);
+    }
+
+    @Override
+    public void require(int type, String namespace, String name)
+            throws XmlPullParserException, IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        if (mCurrentToken != type || !Objects.equals(mCurrentName, name)) {
+            throw new XmlPullParserException(getPositionDescription());
+        }
+    }
+
+    @Override
+    public String nextText() throws XmlPullParserException, IOException {
+        if (getEventType() != START_TAG) {
+            throw new XmlPullParserException(getPositionDescription());
+        }
+        int eventType = next();
+        if (eventType == TEXT) {
+            String result = getText();
+            eventType = next();
+            if (eventType != END_TAG) {
+                throw new XmlPullParserException(getPositionDescription());
+            }
+            return result;
+        } else if (eventType == END_TAG) {
+            return "";
+        } else {
+            throw new XmlPullParserException(getPositionDescription());
+        }
+    }
+
+    @Override
+    public int nextTag() throws XmlPullParserException, IOException {
+        int eventType = next();
+        if (eventType == TEXT && isWhitespace()) {
+            eventType = next();
+        }
+        if (eventType != START_TAG && eventType != END_TAG) {
+            throw new XmlPullParserException(getPositionDescription());
+        }
+        return eventType;
+    }
+
+    /**
+     * Allocate and return a new {@link Attribute} associated with the tag being
+     * currently processed. This will automatically grow the internal pool as
+     * needed.
+     */
+    private @NonNull Attribute obtainAttribute() {
+        if (mAttributeCount == mAttributes.length) {
+            final int before = mAttributes.length;
+            final int after = before + (before >> 1);
+            mAttributes = Arrays.copyOf(mAttributes, after);
+            for (int i = before; i < after; i++) {
+                mAttributes[i] = new Attribute();
+            }
+        }
+        return mAttributes[mAttributeCount++];
+    }
+
+    /**
+     * Clear any {@link Attribute} instances that have been allocated by
+     * {@link #obtainAttribute()}, returning them into the pool for recycling.
+     */
+    private void resetAttributes() {
+        for (int i = 0; i < mAttributeCount; i++) {
+            mAttributes[i].reset();
+        }
+        mAttributeCount = 0;
+    }
+
+    /**
+     * Search through the pool of currently allocated {@link Attribute}
+     * instances for one that matches the given name.
+     */
+    private @NonNull Attribute findAttribute(@NonNull String name) throws IOException {
+        for (int i = 0; i < mAttributeCount; i++) {
+            if (Objects.equals(mAttributes[i].name, name)) {
+                return mAttributes[i];
+            }
+        }
+        throw new IOException("Missing attribute " + name);
+    }
+
+    @Override
+    public String getAttributeValue(String namespace, String name) {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        try {
+            return findAttribute(name).getValueString();
+        } catch (IOException e) {
+            // Missing attributes default to null
+            return null;
+        }
+    }
+
+    @Override
+    public String getAttributeValue(int index) {
+        return mAttributes[index].getValueString();
+    }
+
+    @Override
+    public byte[] getAttributeBytesHex(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueBytesHex();
+    }
+
+    @Override
+    public byte[] getAttributeBytesBase64(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueBytesBase64();
+    }
+
+    @Override
+    public int getAttributeInt(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueInt();
+    }
+
+    @Override
+    public int getAttributeIntHex(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueIntHex();
+    }
+
+    @Override
+    public long getAttributeLong(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueLong();
+    }
+
+    @Override
+    public long getAttributeLongHex(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueLongHex();
+    }
+
+    @Override
+    public float getAttributeFloat(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueFloat();
+    }
+
+    @Override
+    public double getAttributeDouble(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueDouble();
+    }
+
+    @Override
+    public boolean getAttributeBoolean(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        return findAttribute(name).getValueBoolean();
+    }
+
+    @Override
+    public String getText() {
+        return mCurrentText;
+    }
+
+    @Override
+    public char[] getTextCharacters(int[] holderForStartAndLength) {
+        final char[] chars = mCurrentText.toCharArray();
+        holderForStartAndLength[0] = 0;
+        holderForStartAndLength[1] = chars.length;
+        return chars;
+    }
+
+    @Override
+    public String getInputEncoding() {
+        return StandardCharsets.UTF_8.name();
+    }
+
+    @Override
+    public int getDepth() {
+        return mCurrentDepth;
+    }
+
+    @Override
+    public String getPositionDescription() {
+        // Not very helpful, but it's the best information we have
+        return "Token " + mCurrentToken + " at depth " + mCurrentDepth;
+    }
+
+    @Override
+    public int getLineNumber() {
+        return -1;
+    }
+
+    @Override
+    public int getColumnNumber() {
+        return -1;
+    }
+
+    @Override
+    public boolean isWhitespace() throws XmlPullParserException {
+        switch (mCurrentToken) {
+            case IGNORABLE_WHITESPACE:
+                return true;
+            case TEXT:
+            case CDSECT:
+                return !TextUtils.isGraphic(mCurrentText);
+            default:
+                throw new XmlPullParserException("Not applicable for token " + mCurrentToken);
+        }
+    }
+
+    @Override
+    public String getNamespace() {
+        switch (mCurrentToken) {
+            case START_TAG:
+            case END_TAG:
+                // Namespaces are unsupported
+                return NO_NAMESPACE;
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public String getName() {
+        return mCurrentName;
+    }
+
+    @Override
+    public String getPrefix() {
+        // Prefixes are not supported
+        return null;
+    }
+
+    @Override
+    public boolean isEmptyElementTag() throws XmlPullParserException {
+        switch (mCurrentToken) {
+            case START_TAG:
+                try {
+                    return (peekNextExternalToken() == END_TAG);
+                } catch (IOException e) {
+                    throw new XmlPullParserException(e.toString());
+                }
+            default:
+                throw new XmlPullParserException("Not at START_TAG");
+        }
+    }
+
+    @Override
+    public int getAttributeCount() {
+        return mAttributeCount;
+    }
+
+    @Override
+    public String getAttributeNamespace(int index) {
+        // Namespaces are unsupported
+        return NO_NAMESPACE;
+    }
+
+    @Override
+    public String getAttributeName(int index) {
+        return mAttributes[index].name;
+    }
+
+    @Override
+    public String getAttributePrefix(int index) {
+        // Prefixes are not supported
+        return null;
+    }
+
+    @Override
+    public String getAttributeType(int index) {
+        // Validation is not supported
+        return "CDATA";
+    }
+
+    @Override
+    public boolean isAttributeDefault(int index) {
+        // Validation is not supported
+        return false;
+    }
+
+    @Override
+    public int getEventType() throws XmlPullParserException {
+        return mCurrentToken;
+    }
+
+    @Override
+    public int getNamespaceCount(int depth) throws XmlPullParserException {
+        // Namespaces are unsupported
+        return 0;
+    }
+
+    @Override
+    public String getNamespacePrefix(int pos) throws XmlPullParserException {
+        // Namespaces are unsupported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getNamespaceUri(int pos) throws XmlPullParserException {
+        // Namespaces are unsupported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getNamespace(String prefix) {
+        // Namespaces are unsupported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void defineEntityReplacementText(String entityName, String replacementText)
+            throws XmlPullParserException {
+        // Custom entities are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setFeature(String name, boolean state) throws XmlPullParserException {
+        // Features are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean getFeature(String name) {
+        // Features are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setProperty(String name, Object value) throws XmlPullParserException {
+        // Properties are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object getProperty(String name) {
+        // Properties are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    private static IllegalArgumentException illegalNamespace() {
+        throw new IllegalArgumentException("Namespaces are not supported");
+    }
+
+    /**
+     * Holder representing a single attribute. This design enables object
+     * recycling without resorting to autoboxing.
+     * <p>
+     * To support conversion between human-readable XML and binary XML, the
+     * various accessor methods will transparently convert from/to
+     * human-readable values when needed.
+     */
+    private static class Attribute {
+        public String name;
+        public int type;
+
+        public String valueString;
+        public byte[] valueBytes;
+        public int valueInt;
+        public long valueLong;
+        public float valueFloat;
+        public double valueDouble;
+
+        public void reset() {
+            name = null;
+            valueString = null;
+            valueBytes = null;
+        }
+
+        public @Nullable String getValueString() {
+            switch (type) {
+                case TYPE_NULL:
+                    return null;
+                case TYPE_STRING:
+                case TYPE_STRING_INTERNED:
+                    return valueString;
+                case TYPE_BYTES_HEX:
+                    return bytesToHexString(valueBytes);
+                case TYPE_BYTES_BASE64:
+                    return Base64.encodeToString(valueBytes, Base64.NO_WRAP);
+                case TYPE_INT:
+                    return Integer.toString(valueInt);
+                case TYPE_INT_HEX:
+                    return Integer.toString(valueInt, 16);
+                case TYPE_LONG:
+                    return Long.toString(valueLong);
+                case TYPE_LONG_HEX:
+                    return Long.toString(valueLong, 16);
+                case TYPE_FLOAT:
+                    return Float.toString(valueFloat);
+                case TYPE_DOUBLE:
+                    return Double.toString(valueDouble);
+                case TYPE_BOOLEAN_TRUE:
+                    return "true";
+                case TYPE_BOOLEAN_FALSE:
+                    return "false";
+                default:
+                    // Unknown data type; null is the best we can offer
+                    return null;
+            }
+        }
+
+        public @Nullable byte[] getValueBytesHex() throws IOException {
+            switch (type) {
+                case TYPE_NULL:
+                    return null;
+                case TYPE_BYTES_HEX:
+                case TYPE_BYTES_BASE64:
+                    return valueBytes;
+                case TYPE_STRING:
+                    return hexStringToBytes(valueString);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public @Nullable byte[] getValueBytesBase64() throws IOException {
+            switch (type) {
+                case TYPE_NULL:
+                    return null;
+                case TYPE_BYTES_HEX:
+                case TYPE_BYTES_BASE64:
+                    return valueBytes;
+                case TYPE_STRING:
+                    return Base64.decode(valueString, Base64.NO_WRAP);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public int getValueInt() throws IOException {
+            switch (type) {
+                case TYPE_INT:
+                case TYPE_INT_HEX:
+                    return valueInt;
+                case TYPE_STRING:
+                    return Integer.parseInt(valueString);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public int getValueIntHex() throws IOException {
+            switch (type) {
+                case TYPE_INT:
+                case TYPE_INT_HEX:
+                    return valueInt;
+                case TYPE_STRING:
+                    return Integer.parseInt(valueString, 16);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public long getValueLong() throws IOException {
+            switch (type) {
+                case TYPE_LONG:
+                case TYPE_LONG_HEX:
+                    return valueLong;
+                case TYPE_STRING:
+                    return Long.parseLong(valueString);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public long getValueLongHex() throws IOException {
+            switch (type) {
+                case TYPE_LONG:
+                case TYPE_LONG_HEX:
+                    return valueLong;
+                case TYPE_STRING:
+                    return Long.parseLong(valueString, 16);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public float getValueFloat() throws IOException {
+            switch (type) {
+                case TYPE_FLOAT:
+                    return valueFloat;
+                case TYPE_STRING:
+                    return Float.parseFloat(valueString);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public double getValueDouble() throws IOException {
+            switch (type) {
+                case TYPE_DOUBLE:
+                    return valueDouble;
+                case TYPE_STRING:
+                    return Double.parseDouble(valueString);
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+
+        public boolean getValueBoolean() throws IOException {
+            switch (type) {
+                case TYPE_BOOLEAN_TRUE:
+                    return true;
+                case TYPE_BOOLEAN_FALSE:
+                    return false;
+                case TYPE_STRING:
+                    if ("true".equalsIgnoreCase(valueString)) {
+                        return true;
+                    } else if ("false".equalsIgnoreCase(valueString)) {
+                        return false;
+                    } else {
+                        throw new IOException("Invalid boolean: " + valueString);
+                    }
+                default:
+                    throw new IOException("Invalid conversion from " + type);
+            }
+        }
+    }
+
+    // NOTE: To support unbundled clients, we include an inlined copy
+    // of hex conversion logic from HexDump below
+    private final static char[] HEX_DIGITS =
+            { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+    private static int toByte(char c) throws IOException {
+        if (c >= '0' && c <= '9') return (c - '0');
+        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+        throw new IOException("Invalid hex char '" + c + "'");
+    }
+
+    static String bytesToHexString(byte[] value) {
+        final int length = value.length;
+        final char[] buf = new char[length * 2];
+        int bufIndex = 0;
+        for (int i = 0; i < length; i++) {
+            byte b = value[i];
+            buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
+            buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
+        }
+        return new String(buf);
+    }
+
+    static byte[] hexStringToBytes(String value) throws IOException {
+        final int length = value.length();
+        if (length % 2 != 0) {
+            throw new IOException("Invalid hex length " + length);
+        }
+        byte[] buffer = new byte[length / 2];
+        for (int i = 0; i < length; i += 2) {
+            buffer[i / 2] = (byte) ((toByte(value.charAt(i)) << 4)
+                    | toByte(value.charAt(i + 1)));
+        }
+        return buffer;
+    }
+}
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
new file mode 100644
index 0000000..d3fcf71
--- /dev/null
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -0,0 +1,396 @@
+/*
+ * 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.internal.util;
+
+import static org.xmlpull.v1.XmlPullParser.CDSECT;
+import static org.xmlpull.v1.XmlPullParser.COMMENT;
+import static org.xmlpull.v1.XmlPullParser.DOCDECL;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.ENTITY_REF;
+import static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;
+import static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION;
+import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * Serializer that writes XML documents using a custom binary wire protocol
+ * which benchmarking has shown to be 4.3x faster and use 2.4x less disk space
+ * than {@code Xml.newFastSerializer()} for a typical {@code packages.xml}.
+ * <p>
+ * The high-level design of the wire protocol is to directly serialize the event
+ * stream, while efficiently and compactly writing strongly-typed primitives
+ * delivered through the {@link TypedXmlSerializer} interface.
+ * <p>
+ * Each serialized event is a single byte where the lower half is a normal
+ * {@link XmlPullParser} token and the upper half is an optional data type
+ * signal, such as {@link #TYPE_INT}.
+ * <p>
+ * This serializer has some specific limitations:
+ * <ul>
+ * <li>Only the UTF-8 encoding is supported.
+ * <li>Variable length values, such as {@code byte[]} or {@link String}, are
+ * limited to 65,535 bytes in length. Note that {@link String} values are stored
+ * as UTF-8 on the wire.
+ * <li>Namespaces, prefixes, properties, and options are unsupported.
+ * </ul>
+ */
+public final class BinaryXmlSerializer implements TypedXmlSerializer {
+    /**
+     * The wire protocol always begins with a well-known magic value of
+     * {@code ABX_}, representing "Android Binary XML." The final byte is a
+     * version number which may be incremented as the protocol changes.
+     */
+    static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
+
+    /**
+     * Internal token which represents an attribute associated with the most
+     * recent {@link #START_TAG} token.
+     */
+    static final int ATTRIBUTE = 15;
+
+    static final int TYPE_NULL = 1 << 4;
+    static final int TYPE_STRING = 2 << 4;
+    static final int TYPE_STRING_INTERNED = 3 << 4;
+    static final int TYPE_BYTES_HEX = 4 << 4;
+    static final int TYPE_BYTES_BASE64 = 5 << 4;
+    static final int TYPE_INT = 6 << 4;
+    static final int TYPE_INT_HEX = 7 << 4;
+    static final int TYPE_LONG = 8 << 4;
+    static final int TYPE_LONG_HEX = 9 << 4;
+    static final int TYPE_FLOAT = 10 << 4;
+    static final int TYPE_DOUBLE = 11 << 4;
+    static final int TYPE_BOOLEAN_TRUE = 12 << 4;
+    static final int TYPE_BOOLEAN_FALSE = 13 << 4;
+
+    /**
+     * Default buffer size, which matches {@code FastXmlSerializer}. This should
+     * be kept in sync with {@link BinaryXmlPullParser}.
+     */
+    private static final int BUFFER_SIZE = 32_768;
+
+    private FastDataOutput mOut;
+
+    /**
+     * Stack of tags which are currently active via {@link #startTag} and which
+     * haven't been terminated via {@link #endTag}.
+     */
+    private int mTagCount = 0;
+    private String[] mTagNames;
+
+    /**
+     * Write the given token and optional {@link String} into our buffer.
+     */
+    private void writeToken(int token, @Nullable String text) throws IOException {
+        if (text != null) {
+            mOut.writeByte(token | TYPE_STRING);
+            mOut.writeUTF(text);
+        } else {
+            mOut.writeByte(token | TYPE_NULL);
+        }
+    }
+
+    @Override
+    public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {
+        if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+            throw new UnsupportedOperationException();
+        }
+
+        mOut = new FastDataOutput(os, BUFFER_SIZE);
+        mOut.write(PROTOCOL_MAGIC_VERSION_0);
+
+        mTagCount = 0;
+        mTagNames = new String[8];
+    }
+
+    @Override
+    public void setOutput(Writer writer) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        mOut.flush();
+    }
+
+    @Override
+    public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)
+            throws IOException {
+        if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+            throw new UnsupportedOperationException();
+        }
+        mOut.writeByte(START_DOCUMENT | TYPE_NULL);
+    }
+
+    @Override
+    public void endDocument() throws IOException {
+        mOut.writeByte(END_DOCUMENT | TYPE_NULL);
+        flush();
+    }
+
+    @Override
+    public int getDepth() {
+        return mTagCount;
+    }
+
+    @Override
+    public String getNamespace() {
+        // Namespaces are unsupported
+        return XmlPullParser.NO_NAMESPACE;
+    }
+
+    @Override
+    public String getName() {
+        return mTagNames[mTagCount - 1];
+    }
+
+    @Override
+    public XmlSerializer startTag(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        if (mTagCount == mTagNames.length) {
+            mTagNames = Arrays.copyOf(mTagNames, mTagCount + (mTagCount >> 1));
+        }
+        mTagNames[mTagCount++] = name;
+        mOut.writeByte(START_TAG | TYPE_STRING_INTERNED);
+        mOut.writeInternedUTF(name);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer endTag(String namespace, String name) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mTagCount--;
+        mOut.writeByte(END_TAG | TYPE_STRING_INTERNED);
+        mOut.writeInternedUTF(name);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attribute(String namespace, String name, String value) throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_STRING);
+        mOut.writeInternedUTF(name);
+        mOut.writeUTF(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeInterned(String namespace, String name, String value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_STRING_INTERNED);
+        mOut.writeInternedUTF(name);
+        mOut.writeInternedUTF(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX);
+        mOut.writeInternedUTF(name);
+        mOut.writeShort(value.length);
+        mOut.write(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64);
+        mOut.writeInternedUTF(name);
+        mOut.writeShort(value.length);
+        mOut.write(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeInt(String namespace, String name, int value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_INT);
+        mOut.writeInternedUTF(name);
+        mOut.writeInt(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeIntHex(String namespace, String name, int value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_INT_HEX);
+        mOut.writeInternedUTF(name);
+        mOut.writeInt(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeLong(String namespace, String name, long value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_LONG);
+        mOut.writeInternedUTF(name);
+        mOut.writeLong(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeLongHex(String namespace, String name, long value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_LONG_HEX);
+        mOut.writeInternedUTF(name);
+        mOut.writeLong(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeFloat(String namespace, String name, float value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_FLOAT);
+        mOut.writeInternedUTF(name);
+        mOut.writeFloat(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeDouble(String namespace, String name, double value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        mOut.writeByte(ATTRIBUTE | TYPE_DOUBLE);
+        mOut.writeInternedUTF(name);
+        mOut.writeDouble(value);
+        return this;
+    }
+
+    @Override
+    public XmlSerializer attributeBoolean(String namespace, String name, boolean value)
+            throws IOException {
+        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+        if (value) {
+            mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_TRUE);
+            mOut.writeInternedUTF(name);
+        } else {
+            mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_FALSE);
+            mOut.writeInternedUTF(name);
+        }
+        return this;
+    }
+
+    @Override
+    public XmlSerializer text(char[] buf, int start, int len) throws IOException {
+        writeToken(TEXT, new String(buf, start, len));
+        return this;
+    }
+
+    @Override
+    public XmlSerializer text(String text) throws IOException {
+        writeToken(TEXT, text);
+        return this;
+    }
+
+    @Override
+    public void cdsect(String text) throws IOException {
+        writeToken(CDSECT, text);
+    }
+
+    @Override
+    public void entityRef(String text) throws IOException {
+        writeToken(ENTITY_REF, text);
+    }
+
+    @Override
+    public void processingInstruction(String text) throws IOException {
+        writeToken(PROCESSING_INSTRUCTION, text);
+    }
+
+    @Override
+    public void comment(String text) throws IOException {
+        writeToken(COMMENT, text);
+    }
+
+    @Override
+    public void docdecl(String text) throws IOException {
+        writeToken(DOCDECL, text);
+    }
+
+    @Override
+    public void ignorableWhitespace(String text) throws IOException {
+        writeToken(IGNORABLE_WHITESPACE, text);
+    }
+
+    @Override
+    public void setFeature(String name, boolean state) {
+        // Quietly handle no-op features
+        if ("http://xmlpull.org/v1/doc/features.html#indent-output".equals(name)) {
+            return;
+        }
+        // Features are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean getFeature(String name) {
+        // Features are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setProperty(String name, Object value) {
+        // Properties are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object getProperty(String name) {
+        // Properties are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPrefix(String prefix, String namespace) {
+        // Prefixes are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getPrefix(String namespace, boolean generatePrefix) {
+        // Prefixes are not supported
+        throw new UnsupportedOperationException();
+    }
+
+    private static IllegalArgumentException illegalNamespace() {
+        throw new IllegalArgumentException("Namespaces are not supported");
+    }
+}
diff --git a/core/java/com/android/internal/util/FastDataInput.java b/core/java/com/android/internal/util/FastDataInput.java
new file mode 100644
index 0000000..2e8cb47
--- /dev/null
+++ b/core/java/com/android/internal/util/FastDataInput.java
@@ -0,0 +1,256 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Optimized implementation of {@link DataInput} which buffers data in memory
+ * from the underlying {@link InputStream}.
+ * <p>
+ * Benchmarks have demonstrated this class is 3x more efficient than using a
+ * {@link DataInputStream} with a {@link BufferedInputStream}.
+ */
+public class FastDataInput implements DataInput, Closeable {
+    private static final int MAX_UNSIGNED_SHORT = 65_535;
+
+    private final InputStream mIn;
+
+    private final byte[] mBuffer;
+    private final int mBufferCap;
+
+    private int mBufferPos;
+    private int mBufferLim;
+
+    /**
+     * Values that have been "interned" by {@link #readInternedUTF()}.
+     */
+    private int mStringRefCount = 0;
+    private String[] mStringRefs = new String[32];
+
+    public FastDataInput(@NonNull InputStream in, int bufferSize) {
+        mIn = Objects.requireNonNull(in);
+        if (bufferSize < 8) {
+            throw new IllegalArgumentException();
+        }
+
+        mBuffer = new byte[bufferSize];
+        mBufferCap = mBuffer.length;
+    }
+
+    private void fill(int need) throws IOException {
+        final int remain = mBufferLim - mBufferPos;
+        System.arraycopy(mBuffer, mBufferPos, mBuffer, 0, remain);
+        mBufferPos = 0;
+        mBufferLim = remain;
+        need -= remain;
+
+        while (need > 0) {
+            int c = mIn.read(mBuffer, mBufferLim, mBufferCap - mBufferLim);
+            if (c == -1) {
+                throw new EOFException();
+            } else {
+                mBufferLim += c;
+                need -= c;
+            }
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        mIn.close();
+    }
+
+    @Override
+    public void readFully(byte[] b) throws IOException {
+        readFully(b, 0, b.length);
+    }
+
+    @Override
+    public void readFully(byte[] b, int off, int len) throws IOException {
+        // Attempt to read directly from buffer space if there's enough room,
+        // otherwise fall back to chunking into place
+        if (mBufferCap >= len) {
+            if (mBufferLim - mBufferPos < len) fill(len);
+            System.arraycopy(mBuffer, mBufferPos, b, off, len);
+            mBufferPos += len;
+        } else {
+            final int remain = mBufferLim - mBufferPos;
+            System.arraycopy(mBuffer, mBufferPos, b, off, remain);
+            mBufferPos += remain;
+            off += remain;
+            len -= remain;
+
+            while (len > 0) {
+                int c = mIn.read(b, off, len);
+                if (c == -1) {
+                    throw new EOFException();
+                } else {
+                    off += c;
+                    len -= c;
+                }
+            }
+        }
+    }
+
+    @Override
+    public String readUTF() throws IOException {
+        // Attempt to read directly from buffer space if there's enough room,
+        // otherwise fall back to chunking into place
+        final int len = readUnsignedShort();
+        if (mBufferCap >= len) {
+            if (mBufferLim - mBufferPos < len) fill(len);
+            final String res = new String(mBuffer, mBufferPos, len, StandardCharsets.UTF_8);
+            mBufferPos += len;
+            return res;
+        } else {
+            final byte[] tmp = new byte[len];
+            readFully(tmp, 0, tmp.length);
+            return new String(tmp, StandardCharsets.UTF_8);
+        }
+    }
+
+    /**
+     * Read a {@link String} value with the additional signal that the given
+     * value is a candidate for being canonicalized, similar to
+     * {@link String#intern()}.
+     * <p>
+     * Canonicalization is implemented by writing each unique string value once
+     * the first time it appears, and then writing a lightweight {@code short}
+     * reference when that string is written again in the future.
+     *
+     * @see FastDataOutput#writeInternedUTF(String)
+     */
+    public @NonNull String readInternedUTF() throws IOException {
+        final int ref = readUnsignedShort();
+        if (ref == MAX_UNSIGNED_SHORT) {
+            final String s = readUTF();
+
+            // We can only safely intern when we have remaining values; if we're
+            // full we at least sent the string value above
+            if (mStringRefCount < MAX_UNSIGNED_SHORT) {
+                if (mStringRefCount == mStringRefs.length) {
+                    mStringRefs = Arrays.copyOf(mStringRefs,
+                            mStringRefCount + (mStringRefCount >> 1));
+                }
+                mStringRefs[mStringRefCount++] = s;
+            }
+
+            return s;
+        } else {
+            return mStringRefs[ref];
+        }
+    }
+
+    @Override
+    public boolean readBoolean() throws IOException {
+        return readByte() != 0;
+    }
+
+    /**
+     * Returns the same decoded value as {@link #readByte()} but without
+     * actually consuming the underlying data.
+     */
+    public byte peekByte() throws IOException {
+        if (mBufferLim - mBufferPos < 1) fill(1);
+        return mBuffer[mBufferPos];
+    }
+
+    @Override
+    public byte readByte() throws IOException {
+        if (mBufferLim - mBufferPos < 1) fill(1);
+        return mBuffer[mBufferPos++];
+    }
+
+    @Override
+    public int readUnsignedByte() throws IOException {
+        return Byte.toUnsignedInt(readByte());
+    }
+
+    @Override
+    public short readShort() throws IOException {
+        if (mBufferLim - mBufferPos < 2) fill(2);
+        return (short) (((mBuffer[mBufferPos++] & 0xff) <<  8) |
+                        ((mBuffer[mBufferPos++] & 0xff) <<  0));
+    }
+
+    @Override
+    public int readUnsignedShort() throws IOException {
+        return Short.toUnsignedInt((short) readShort());
+    }
+
+    @Override
+    public char readChar() throws IOException {
+        return (char) readShort();
+    }
+
+    @Override
+    public int readInt() throws IOException {
+        if (mBufferLim - mBufferPos < 4) fill(4);
+        return (((mBuffer[mBufferPos++] & 0xff) << 24) |
+                ((mBuffer[mBufferPos++] & 0xff) << 16) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  8) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  0));
+    }
+
+    @Override
+    public long readLong() throws IOException {
+        if (mBufferLim - mBufferPos < 8) fill(8);
+        int h = ((mBuffer[mBufferPos++] & 0xff) << 24) |
+                ((mBuffer[mBufferPos++] & 0xff) << 16) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  8) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  0);
+        int l = ((mBuffer[mBufferPos++] & 0xff) << 24) |
+                ((mBuffer[mBufferPos++] & 0xff) << 16) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  8) |
+                ((mBuffer[mBufferPos++] & 0xff) <<  0);
+        return (((long) h) << 32L) | ((long) l) & 0xffffffffL;
+    }
+
+    @Override
+    public float readFloat() throws IOException {
+        return Float.intBitsToFloat(readInt());
+    }
+
+    @Override
+    public double readDouble() throws IOException {
+        return Double.longBitsToDouble(readLong());
+    }
+
+    @Override
+    public int skipBytes(int n) throws IOException {
+        // Callers should read data piecemeal
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String readLine() throws IOException {
+        // Callers should read data piecemeal
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/core/java/com/android/internal/util/FastDataOutput.java b/core/java/com/android/internal/util/FastDataOutput.java
new file mode 100644
index 0000000..2530501
--- /dev/null
+++ b/core/java/com/android/internal/util/FastDataOutput.java
@@ -0,0 +1,228 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+import android.util.CharsetUtils;
+
+import dalvik.system.VMRuntime;
+
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * Optimized implementation of {@link DataOutput} which buffers data in memory
+ * before flushing to the underlying {@link OutputStream}.
+ * <p>
+ * Benchmarks have demonstrated this class is 2x more efficient than using a
+ * {@link DataOutputStream} with a {@link BufferedOutputStream}.
+ */
+public class FastDataOutput implements DataOutput, Flushable, Closeable {
+    private static final int MAX_UNSIGNED_SHORT = 65_535;
+
+    private final OutputStream mOut;
+
+    private final byte[] mBuffer;
+    private final long mBufferPtr;
+    private final int mBufferCap;
+
+    private int mBufferPos;
+
+    /**
+     * Values that have been "interned" by {@link #writeInternedUTF(String)}.
+     */
+    private HashMap<String, Short> mStringRefs = new HashMap<>();
+
+    public FastDataOutput(@NonNull OutputStream out, int bufferSize) {
+        mOut = Objects.requireNonNull(out);
+        if (bufferSize < 8) {
+            throw new IllegalArgumentException();
+        }
+
+        mBuffer = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, bufferSize);
+        mBufferPtr = VMRuntime.getRuntime().addressOf(mBuffer);
+        mBufferCap = mBuffer.length;
+    }
+
+    private void drain() throws IOException {
+        if (mBufferPos > 0) {
+            mOut.write(mBuffer, 0, mBufferPos);
+            mBufferPos = 0;
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        drain();
+        mOut.flush();
+    }
+
+    @Override
+    public void close() throws IOException {
+        mOut.close();
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        writeByte(b);
+    }
+
+    @Override
+    public void write(byte[] b) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (mBufferCap < len) {
+            drain();
+            mOut.write(b, off, len);
+        } else {
+            if (mBufferCap - mBufferPos < len) drain();
+            System.arraycopy(b, off, mBuffer, mBufferPos, len);
+            mBufferPos += len;
+        }
+    }
+
+    @Override
+    public void writeUTF(String s) throws IOException {
+        // Attempt to write directly to buffer space if there's enough room,
+        // otherwise fall back to chunking into place
+        if (mBufferCap - mBufferPos < 2 + s.length()) drain();
+        final int res = CharsetUtils.toUtf8Bytes(s, mBufferPtr, mBufferPos + 2,
+                mBufferCap - mBufferPos - 2);
+        if (res >= 0) {
+            if (res > MAX_UNSIGNED_SHORT) {
+                throw new IOException("UTF-8 length too large: " + res);
+            }
+            writeShort(res);
+            mBufferPos += res;
+        } else {
+            final byte[] tmp = s.getBytes(StandardCharsets.UTF_8);
+            if (tmp.length > MAX_UNSIGNED_SHORT) {
+                throw new IOException("UTF-8 length too large: " + res);
+            }
+            writeShort(tmp.length);
+            write(tmp, 0, tmp.length);
+        }
+    }
+
+    /**
+     * Write a {@link String} value with the additional signal that the given
+     * value is a candidate for being canonicalized, similar to
+     * {@link String#intern()}.
+     * <p>
+     * Canonicalization is implemented by writing each unique string value once
+     * the first time it appears, and then writing a lightweight {@code short}
+     * reference when that string is written again in the future.
+     *
+     * @see FastDataInput#readInternedUTF()
+     */
+    public void writeInternedUTF(@NonNull String s) throws IOException {
+        Short ref = mStringRefs.get(s);
+        if (ref != null) {
+            writeShort(ref);
+        } else {
+            writeShort(MAX_UNSIGNED_SHORT);
+            writeUTF(s);
+
+            // We can only safely intern when we have remaining values; if we're
+            // full we at least sent the string value above
+            ref = (short) mStringRefs.size();
+            if (ref < MAX_UNSIGNED_SHORT) {
+                mStringRefs.put(s, ref);
+            }
+        }
+    }
+
+    @Override
+    public void writeBoolean(boolean v) throws IOException {
+        writeByte(v ? 1 : 0);
+    }
+
+    @Override
+    public void writeByte(int v) throws IOException {
+        if (mBufferCap - mBufferPos < 1) drain();
+        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);
+    }
+
+    @Override
+    public void writeShort(int v) throws IOException {
+        if (mBufferCap - mBufferPos < 2) drain();
+        mBuffer[mBufferPos++] = (byte) ((v >>  8) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);
+    }
+
+    @Override
+    public void writeChar(int v) throws IOException {
+        writeShort((short) v);
+    }
+
+    @Override
+    public void writeInt(int v) throws IOException {
+        if (mBufferCap - mBufferPos < 4) drain();
+        mBuffer[mBufferPos++] = (byte) ((v >> 24) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((v >> 16) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((v >>  8) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);
+    }
+
+    @Override
+    public void writeLong(long v) throws IOException {
+        if (mBufferCap - mBufferPos < 8) drain();
+        int i = (int) (v >> 32);
+        mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >>  8) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >>  0) & 0xff);
+        i = (int) v;
+        mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >>  8) & 0xff);
+        mBuffer[mBufferPos++] = (byte) ((i >>  0) & 0xff);
+    }
+
+    @Override
+    public void writeFloat(float v) throws IOException {
+        writeInt(Float.floatToIntBits(v));
+    }
+
+    @Override
+    public void writeDouble(double v) throws IOException {
+        writeLong(Double.doubleToLongBits(v));
+    }
+
+    @Override
+    public void writeBytes(String s) throws IOException {
+        // Callers should use writeUTF()
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void writeChars(String s) throws IOException {
+        // Callers should use writeUTF()
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/core/java/com/android/internal/util/XmlPullParserWrapper.java b/core/java/com/android/internal/util/XmlPullParserWrapper.java
new file mode 100644
index 0000000..efa17ef
--- /dev/null
+++ b/core/java/com/android/internal/util/XmlPullParserWrapper.java
@@ -0,0 +1,189 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Objects;
+
+/**
+ * Wrapper which delegates all calls through to the given {@link XmlPullParser}.
+ */
+public class XmlPullParserWrapper implements XmlPullParser {
+    private final XmlPullParser mWrapped;
+
+    public XmlPullParserWrapper(@NonNull XmlPullParser wrapped) {
+        mWrapped = Objects.requireNonNull(wrapped);
+    }
+
+    public void setFeature(String name, boolean state) throws XmlPullParserException {
+        mWrapped.setFeature(name, state);
+    }
+
+    public boolean getFeature(String name) {
+        return mWrapped.getFeature(name);
+    }
+
+    public void setProperty(String name, Object value) throws XmlPullParserException {
+        mWrapped.setProperty(name, value);
+    }
+
+    public Object getProperty(String name) {
+        return mWrapped.getProperty(name);
+    }
+
+    public void setInput(Reader in) throws XmlPullParserException {
+        mWrapped.setInput(in);
+    }
+
+    public void setInput(InputStream inputStream, String inputEncoding)
+            throws XmlPullParserException {
+        mWrapped.setInput(inputStream, inputEncoding);
+    }
+
+    public String getInputEncoding() {
+        return mWrapped.getInputEncoding();
+    }
+
+    public void defineEntityReplacementText(String entityName, String replacementText)
+            throws XmlPullParserException {
+        mWrapped.defineEntityReplacementText(entityName, replacementText);
+    }
+
+    public int getNamespaceCount(int depth) throws XmlPullParserException {
+        return mWrapped.getNamespaceCount(depth);
+    }
+
+    public String getNamespacePrefix(int pos) throws XmlPullParserException {
+        return mWrapped.getNamespacePrefix(pos);
+    }
+
+    public String getNamespaceUri(int pos) throws XmlPullParserException {
+        return mWrapped.getNamespaceUri(pos);
+    }
+
+    public String getNamespace(String prefix) {
+        return mWrapped.getNamespace(prefix);
+    }
+
+    public int getDepth() {
+        return mWrapped.getDepth();
+    }
+
+    public String getPositionDescription() {
+        return mWrapped.getPositionDescription();
+    }
+
+    public int getLineNumber() {
+        return mWrapped.getLineNumber();
+    }
+
+    public int getColumnNumber() {
+        return mWrapped.getColumnNumber();
+    }
+
+    public boolean isWhitespace() throws XmlPullParserException {
+        return mWrapped.isWhitespace();
+    }
+
+    public String getText() {
+        return mWrapped.getText();
+    }
+
+    public char[] getTextCharacters(int[] holderForStartAndLength) {
+        return mWrapped.getTextCharacters(holderForStartAndLength);
+    }
+
+    public String getNamespace() {
+        return mWrapped.getNamespace();
+    }
+
+    public String getName() {
+        return mWrapped.getName();
+    }
+
+    public String getPrefix() {
+        return mWrapped.getPrefix();
+    }
+
+    public boolean isEmptyElementTag() throws XmlPullParserException {
+        return mWrapped.isEmptyElementTag();
+    }
+
+    public int getAttributeCount() {
+        return mWrapped.getAttributeCount();
+    }
+
+    public String getAttributeNamespace(int index) {
+        return mWrapped.getAttributeNamespace(index);
+    }
+
+    public String getAttributeName(int index) {
+        return mWrapped.getAttributeName(index);
+    }
+
+    public String getAttributePrefix(int index) {
+        return mWrapped.getAttributePrefix(index);
+    }
+
+    public String getAttributeType(int index) {
+        return mWrapped.getAttributeType(index);
+    }
+
+    public boolean isAttributeDefault(int index) {
+        return mWrapped.isAttributeDefault(index);
+    }
+
+    public String getAttributeValue(int index) {
+        return mWrapped.getAttributeValue(index);
+    }
+
+    public String getAttributeValue(String namespace, String name) {
+        return mWrapped.getAttributeValue(namespace, name);
+    }
+
+    public int getEventType() throws XmlPullParserException {
+        return mWrapped.getEventType();
+    }
+
+    public int next() throws XmlPullParserException, IOException {
+        return mWrapped.next();
+    }
+
+    public int nextToken() throws XmlPullParserException, IOException {
+        return mWrapped.nextToken();
+    }
+
+    public void require(int type, String namespace, String name)
+            throws XmlPullParserException, IOException {
+        mWrapped.require(type, namespace, name);
+    }
+
+    public String nextText() throws XmlPullParserException, IOException {
+        return mWrapped.nextText();
+    }
+
+    public int nextTag() throws XmlPullParserException, IOException {
+        return mWrapped.nextTag();
+    }
+}
diff --git a/core/java/com/android/internal/util/XmlSerializerWrapper.java b/core/java/com/android/internal/util/XmlSerializerWrapper.java
new file mode 100644
index 0000000..2131db0
--- /dev/null
+++ b/core/java/com/android/internal/util/XmlSerializerWrapper.java
@@ -0,0 +1,140 @@
+/*
+ * 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.internal.util;
+
+import android.annotation.NonNull;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.Objects;
+
+/**
+ * Wrapper which delegates all calls through to the given {@link XmlSerializer}.
+ */
+public class XmlSerializerWrapper {
+    private final XmlSerializer mWrapped;
+
+    public XmlSerializerWrapper(@NonNull XmlSerializer wrapped) {
+        mWrapped = Objects.requireNonNull(wrapped);
+    }
+
+    public void setFeature(String name, boolean state) {
+        mWrapped.setFeature(name, state);
+    }
+
+    public boolean getFeature(String name) {
+        return mWrapped.getFeature(name);
+    }
+
+    public void setProperty(String name, Object value) {
+        mWrapped.setProperty(name, value);
+    }
+
+    public Object getProperty(String name) {
+        return mWrapped.getProperty(name);
+    }
+
+    public void setOutput(OutputStream os, String encoding) throws IOException {
+        mWrapped.setOutput(os, encoding);
+    }
+
+    public void setOutput(Writer writer)
+            throws IOException, IllegalArgumentException, IllegalStateException {
+        mWrapped.setOutput(writer);
+    }
+
+    public void startDocument(String encoding, Boolean standalone) throws IOException {
+        mWrapped.startDocument(encoding, standalone);
+    }
+
+    public void endDocument() throws IOException {
+        mWrapped.endDocument();
+    }
+
+    public void setPrefix(String prefix, String namespace) throws IOException {
+        mWrapped.setPrefix(prefix, namespace);
+    }
+
+    public String getPrefix(String namespace, boolean generatePrefix) {
+        return mWrapped.getPrefix(namespace, generatePrefix);
+    }
+
+    public int getDepth() {
+        return mWrapped.getDepth();
+    }
+
+    public String getNamespace() {
+        return mWrapped.getNamespace();
+    }
+
+    public String getName() {
+        return mWrapped.getName();
+    }
+
+    public XmlSerializer startTag(String namespace, String name) throws IOException {
+        return mWrapped.startTag(namespace, name);
+    }
+
+    public XmlSerializer attribute(String namespace, String name, String value)
+            throws IOException {
+        return mWrapped.attribute(namespace, name, value);
+    }
+
+    public XmlSerializer endTag(String namespace, String name) throws IOException {
+        return mWrapped.endTag(namespace, name);
+    }
+
+    public XmlSerializer text(String text) throws IOException{
+        return mWrapped.text(text);
+    }
+
+    public XmlSerializer text(char[] buf, int start, int len) throws IOException {
+        return mWrapped.text(buf, start, len);
+    }
+
+    public void cdsect(String text)
+            throws IOException, IllegalArgumentException, IllegalStateException {
+        mWrapped.cdsect(text);
+    }
+
+    public void entityRef(String text) throws IOException {
+        mWrapped.entityRef(text);
+    }
+
+    public void processingInstruction(String text) throws IOException {
+        mWrapped.processingInstruction(text);
+    }
+
+    public void comment(String text) throws IOException {
+        mWrapped.comment(text);
+    }
+
+    public void docdecl(String text) throws IOException {
+        mWrapped.docdecl(text);
+    }
+
+    public void ignorableWhitespace(String text) throws IOException {
+        mWrapped.ignorableWhitespace(text);
+    }
+
+    public void flush() throws IOException {
+        mWrapped.flush();
+    }
+}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index bd6b950..cdd0e04 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
@@ -24,6 +25,8 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Base64;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import libcore.util.HexEncoding;
@@ -48,9 +51,193 @@
 
 /** {@hide} */
 public class XmlUtils {
-
     private static final String STRING_ARRAY_SEPARATOR = ":";
 
+    private static class ForcedTypedXmlSerializer extends XmlSerializerWrapper
+            implements TypedXmlSerializer {
+        public ForcedTypedXmlSerializer(XmlSerializer wrapped) {
+            super(wrapped);
+        }
+
+        @Override
+        public XmlSerializer attributeInterned(String namespace, String name, String value)
+                throws IOException {
+            return attribute(namespace, name, value);
+        }
+
+        @Override
+        public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)
+                throws IOException {
+            return attribute(namespace, name, HexDump.toHexString(value));
+        }
+
+        @Override
+        public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
+                throws IOException {
+            return attribute(namespace, name, Base64.encodeToString(value, Base64.NO_WRAP));
+        }
+
+        @Override
+        public XmlSerializer attributeInt(String namespace, String name, int value)
+                throws IOException {
+            return attribute(namespace, name, Integer.toString(value));
+        }
+
+        @Override
+        public XmlSerializer attributeIntHex(String namespace, String name, int value)
+                throws IOException {
+            return attribute(namespace, name, Integer.toString(value, 16));
+        }
+
+        @Override
+        public XmlSerializer attributeLong(String namespace, String name, long value)
+                throws IOException {
+            return attribute(namespace, name, Long.toString(value));
+        }
+
+        @Override
+        public XmlSerializer attributeLongHex(String namespace, String name, long value)
+                throws IOException {
+            return attribute(namespace, name, Long.toString(value, 16));
+        }
+
+        @Override
+        public XmlSerializer attributeFloat(String namespace, String name, float value)
+                throws IOException {
+            return attribute(namespace, name, Float.toString(value));
+        }
+
+        @Override
+        public XmlSerializer attributeDouble(String namespace, String name, double value)
+                throws IOException {
+            return attribute(namespace, name, Double.toString(value));
+        }
+
+        @Override
+        public XmlSerializer attributeBoolean(String namespace, String name, boolean value)
+                throws IOException {
+            return attribute(namespace, name, Boolean.toString(value));
+        }
+    }
+
+    /**
+     * Return a specialization of the given {@link XmlSerializer} which has
+     * explicit methods to support consistent and efficient conversion of
+     * primitive data types.
+     */
+    public static @NonNull TypedXmlSerializer makeTyped(@NonNull XmlSerializer xml) {
+        if (xml instanceof TypedXmlSerializer) {
+            return (TypedXmlSerializer) xml;
+        } else {
+            return new ForcedTypedXmlSerializer(xml);
+        }
+    }
+
+    private static class ForcedTypedXmlPullParser extends XmlPullParserWrapper
+            implements TypedXmlPullParser {
+        public ForcedTypedXmlPullParser(XmlPullParser wrapped) {
+            super(wrapped);
+        }
+
+        @Override
+        public byte[] getAttributeBytesHex(String namespace, String name) throws IOException {
+            try {
+                return HexDump.hexStringToByteArray(getAttributeValue(namespace, name));
+            } catch (Exception e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public byte[] getAttributeBytesBase64(String namespace, String name) throws IOException {
+            try {
+                return Base64.decode(getAttributeValue(namespace, name), Base64.NO_WRAP);
+            } catch (Exception e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public int getAttributeInt(String namespace, String name) throws IOException {
+            try {
+                return Integer.parseInt(getAttributeValue(namespace, name));
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public int getAttributeIntHex(String namespace, String name) throws IOException {
+            try {
+                return Integer.parseInt(getAttributeValue(namespace, name), 16);
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public long getAttributeLong(String namespace, String name) throws IOException {
+            try {
+                return Long.parseLong(getAttributeValue(namespace, name));
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public long getAttributeLongHex(String namespace, String name) throws IOException {
+            try {
+                return Long.parseLong(getAttributeValue(namespace, name), 16);
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public float getAttributeFloat(String namespace, String name) throws IOException {
+            try {
+                return Float.parseFloat(getAttributeValue(namespace, name));
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public double getAttributeDouble(String namespace, String name) throws IOException {
+            try {
+                return Double.parseDouble(getAttributeValue(namespace, name));
+            } catch (NumberFormatException e) {
+                throw new IOException("Invalid attribute " + name, e);
+            }
+        }
+
+        @Override
+        public boolean getAttributeBoolean(String namespace, String name) throws IOException {
+            final String value = getAttributeValue(namespace, name);
+            if ("true".equalsIgnoreCase(value)) {
+                return true;
+            } else if ("false".equalsIgnoreCase(value)) {
+                return false;
+            } else {
+                throw new IOException("Invalid attribute " + name,
+                        new IllegalArgumentException("For input string: \"" + value + "\""));
+            }
+        }
+    }
+
+    /**
+     * Return a specialization of the given {@link XmlPullParser} which has
+     * explicit methods to support consistent and efficient conversion of
+     * primitive data types.
+     */
+    public static @NonNull TypedXmlPullParser makeTyped(@NonNull XmlPullParser xml) {
+        if (xml instanceof TypedXmlPullParser) {
+            return (TypedXmlPullParser) xml;
+        } else {
+            return new ForcedTypedXmlPullParser(xml);
+        }
+    }
+
     @UnsupportedAppUsage
     public static void skipCurrentTag(XmlPullParser parser)
             throws XmlPullParserException, IOException {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index dd1c87b..8c83d7c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -134,6 +134,7 @@
                 "android_service_DataLoaderService.cpp",
                 "android_util_AssetManager.cpp",
                 "android_util_Binder.cpp",
+                "android_util_CharsetUtils.cpp",
                 "android_util_MemoryIntArray.cpp",
                 "android_util_Process.cpp",
                 "android_media_AudioDeviceAttributes.cpp",
@@ -337,9 +338,6 @@
                 "libhidlbase", // libhwbinder is in here
             ],
         },
-        windows: {
-            enabled: true,
-        },
     },
 
     product_variables: {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 27b23bd..14e74a8 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -105,6 +105,7 @@
  */
 extern int register_android_app_admin_SecurityLog(JNIEnv* env);
 extern int register_android_content_AssetManager(JNIEnv* env);
+extern int register_android_util_CharsetUtils(JNIEnv* env);
 extern int register_android_util_EventLog(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
@@ -1449,6 +1450,7 @@
         REG_JNI(register_com_android_internal_os_RuntimeInit),
         REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
         REG_JNI(register_android_os_SystemClock),
+        REG_JNI(register_android_util_CharsetUtils),
         REG_JNI(register_android_util_EventLog),
         REG_JNI(register_android_util_Log),
         REG_JNI(register_android_util_MemoryIntArray),
diff --git a/core/jni/android_util_CharsetUtils.cpp b/core/jni/android_util_CharsetUtils.cpp
new file mode 100644
index 0000000..3e1d4a7
--- /dev/null
+++ b/core/jni/android_util_CharsetUtils.cpp
@@ -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.
+ */
+
+#include "core_jni_helpers.h"
+#include "nativehelper/scoped_primitive_array.h"
+
+namespace android {
+
+static jint android_util_CharsetUtils_toUtf8Bytes(JNIEnv *env, jobject clazz,
+        jstring src, jint srcLen, jlong dest, jint destOff, jint destLen) {
+    char *destPtr = reinterpret_cast<char*>(dest);
+
+    // Quickly check if destination has plenty of room for worst-case
+    // 4-bytes-per-char encoded size
+    if (destOff >= 0 && destOff + (srcLen * 4) < destLen) {
+        env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
+        return strlen(destPtr + destOff + srcLen) + srcLen;
+    }
+
+    // String still might fit in destination, but we need to measure
+    // its actual encoded size to be sure
+    const size_t encodedLen = env->GetStringUTFLength(src);
+    if (destOff >= 0 && destOff + encodedLen < destLen) {
+        env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
+        return encodedLen;
+    }
+
+    return -1;
+}
+
+static const JNINativeMethod methods[] = {
+    // @FastNative
+    {"toUtf8Bytes",      "(Ljava/lang/String;IJII)I",
+            (void*)android_util_CharsetUtils_toUtf8Bytes},
+};
+
+int register_android_util_CharsetUtils(JNIEnv *env) {
+    return RegisterMethodsOrDie(env, "android/util/CharsetUtils", methods, NELEM(methods));
+}
+
+}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index f791cb1..6ffafc1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -787,10 +787,14 @@
   PrepareDir(dir, mode, uid, gid, fail_fn);
 }
 
+static bool BindMount(const std::string& source_dir, const std::string& target_dir) {
+  return !(TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
+                                    MS_BIND | MS_REC, nullptr)) == -1);
+}
+
 static void BindMount(const std::string& source_dir, const std::string& target_dir,
                       fail_fn_t fail_fn) {
-  if (TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
-                               MS_BIND | MS_REC, nullptr)) == -1) {
+  if (!BindMount(source_dir, target_dir)) {
     fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
                          source_dir.c_str(), target_dir.c_str(), strerror(errno)));
   }
@@ -1168,9 +1172,9 @@
 
 // Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
 // from the actual app data directory in data mirror.
-static void createAndMountAppData(std::string_view package_name,
+static bool createAndMountAppData(std::string_view package_name,
     std::string_view mirror_pkg_dir_name, std::string_view mirror_data_path,
-    std::string_view actual_data_path, fail_fn_t fail_fn) {
+    std::string_view actual_data_path, fail_fn_t fail_fn, bool call_fail_fn) {
 
   char mirrorAppDataPath[PATH_MAX];
   char actualAppDataPath[PATH_MAX];
@@ -1181,6 +1185,29 @@
   PrepareDir(actualAppDataPath, 0700, AID_ROOT, AID_ROOT, fail_fn);
 
   // Bind mount from original app data directory in mirror.
+  if (call_fail_fn) {
+    BindMount(mirrorAppDataPath, actualAppDataPath, fail_fn);
+  } else if(!BindMount(mirrorAppDataPath, actualAppDataPath)) {
+    ALOGW("Failed to mount %s to %s: %s",
+          mirrorAppDataPath, actualAppDataPath, strerror(errno));
+    return false;
+  }
+  return true;
+}
+
+// There is an app data directory over tmpfs overlaid CE / DE storage
+// bind mount it from the actual app data directory in data mirror.
+static void mountAppData(std::string_view package_name,
+    std::string_view mirror_pkg_dir_name, std::string_view mirror_data_path,
+    std::string_view actual_data_path, fail_fn_t fail_fn) {
+
+  char mirrorAppDataPath[PATH_MAX];
+  char actualAppDataPath[PATH_MAX];
+  snprintf(mirrorAppDataPath, PATH_MAX, "%s/%s", mirror_data_path.data(),
+      mirror_pkg_dir_name.data());
+  snprintf(actualAppDataPath, PATH_MAX, "%s/%s", actual_data_path.data(), package_name.data());
+
+  // Bind mount from original app data directory in mirror.
   BindMount(mirrorAppDataPath, actualAppDataPath, fail_fn);
 }
 
@@ -1258,10 +1285,17 @@
   snprintf(mirrorCePath, PATH_MAX, "%s/%d", mirrorCeParent, userId);
   snprintf(mirrorDePath, PATH_MAX, "/data_mirror/data_de/%s/%d", volume_uuid.data(), userId);
 
-  createAndMountAppData(package_name, package_name, mirrorDePath, actualDePath, fail_fn);
+  createAndMountAppData(package_name, package_name, mirrorDePath, actualDePath, fail_fn,
+                        true /*call_fail_fn*/);
 
   std::string ce_data_path = getAppDataDirName(mirrorCePath, package_name, ce_data_inode, fail_fn);
-  createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
+  if (!createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn,
+                             false /*call_fail_fn*/)) {
+    // CE might unlocks and the name is decrypted
+    // get the name and mount again
+    ce_data_path=getAppDataDirName(mirrorCePath, package_name, ce_data_inode, fail_fn);
+    mountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
+  }
 }
 
 // Relabel directory
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 68e01f6..06a71cb 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,17 +33,6 @@
 
 // Static whitelist of open paths that the zygote is allowed to keep open.
 static const char* kPathWhitelist[] = {
-        "/apex/com.android.appsearch/javalib/framework-appsearch.jar",
-        "/apex/com.android.conscrypt/javalib/conscrypt.jar",
-        "/apex/com.android.ipsec/javalib/ike.jar",
-        "/apex/com.android.i18n/javalib/core-icu4j.jar",
-        "/apex/com.android.media/javalib/updatable-media.jar",
-        "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
-        "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
-        "/apex/com.android.permission/javalib/framework-permission.jar",
-        "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar",
-        "/apex/com.android.wifi/javalib/framework-wifi.jar",
-        "/apex/com.android.tethering/javalib/framework-tethering.jar",
         "/dev/null",
         "/dev/socket/zygote",
         "/dev/socket/zygote_secondary",
@@ -103,11 +92,12 @@
     }
   }
 
-  // Jars from the ART APEX are allowed.
-  static const char* kArtApexPrefix = "/apex/com.android.art/javalib/";
-  if (android::base::StartsWith(path, kArtApexPrefix)
-      && android::base::EndsWith(path, kJarSuffix)) {
-    return true;
+  // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
+  static const char* kApexPrefix = "/apex/";
+  static const char* kApexJavalibPathSuffix = "/javalib";
+  if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
+      android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
+      return true;
   }
 
   // the in-memory file created by ART through memfd_create is allowed.
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index d46da87..a2a7649 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2786,4 +2786,9 @@
     // CATEGORY: SETTINGS
     // OS: S
     LOCATION_TIME_ZONE_DETECTION = 1854;
+
+    // OPEN: Settings > Developer options > Media transcode settings
+    // CATEGORY: SETTINGS
+    // OS: S
+    TRANSCODE_SETTINGS = 1855;
 }
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 1ea1baf..abbe25d 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -535,7 +535,7 @@
         // If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
         // Secure#LOCATION_MODE_OFF} temporarily for all users.
         optional SettingProto global_kill_switch = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto gnss_satellite_blacklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gnss_satellite_blocklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto gnss_hal_location_request_duration_millis = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Packages that are whitelisted for ignoring location settings (during emergencies)
         optional SettingProto ignore_settings_package_whitelist = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1550763..fbc5287 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5195,6 +5195,13 @@
     <permission android:name="android.permission.CONTROL_DEVICE_STATE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by an {@link android.service.attestation.ImpressionAttestationService}
+         to ensure that only the system can bind to it.
+         @hide This is not a third-party API (intended for OEMs and system apps).
+    -->
+    <permission android:name="android.permission.BIND_IMPRESSION_ATTESTATION_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Attribution for Geofencing service. -->
     <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
     <!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index df447af..4d45791 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -954,7 +954,7 @@
     <string name="autofill_district" msgid="6428712062213557327">"Districte"</string>
     <string name="autofill_department" msgid="9047276226873531529">"Departament"</string>
     <string name="autofill_prefecture" msgid="7267397763720241872">"Prefectura"</string>
-    <string name="autofill_parish" msgid="6847960518334530198">"Districte"</string>
+    <string name="autofill_parish" msgid="6847960518334530198">"Parròquia"</string>
     <string name="autofill_area" msgid="8289022370678448983">"Àrea"</string>
     <string name="autofill_emirate" msgid="2544082046790551168">"Emirat"</string>
     <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"lectura dels marcadors i l\'historial web"</string>
@@ -1228,8 +1228,8 @@
     <string name="volume_music" msgid="7727274216734955095">"Volum de multimèdia"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"S\'està reproduint per Bluetooth"</string>
     <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_call" msgid="7625321655265747433">"Volum a la trucada"</string>
+    <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volum a la trucada per Bluetooth"</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>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 69d1526..7a0a0ed 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1225,7 +1225,7 @@
     <string name="dump_heap_ready_text" msgid="5849618132123045516">"Protsessi <xliff:g id="PROC">%1$s</xliff:g> mälutõmmis on jagamiseks saadaval. Olge ettevaatlik: see mälutõmmis võib sisaldada tundlikke isiklikke andmeid, millele protsessil on juurdepääs. See võib hõlmata teie sisestatud teavet."</string>
     <string name="sendText" msgid="493003724401350724">"Valige teksti jaoks toiming"</string>
     <string name="volume_ringtone" msgid="134784084629229029">"Helina helitugevus"</string>
-    <string name="volume_music" msgid="7727274216734955095">"Meediumi helitugevus"</string>
+    <string name="volume_music" msgid="7727274216734955095">"Meedia helitugevus"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Esitatakse Bluetoothi kaudu"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Valitud on hääletu märguanne"</string>
     <string name="volume_call" msgid="7625321655265747433">"Kõne helitugevus"</string>
@@ -1236,7 +1236,7 @@
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetoothi maht"</string>
     <string name="volume_icon_description_ringer" msgid="2187800636867423459">"Helina tugevus"</string>
     <string name="volume_icon_description_incall" msgid="4491255105381227919">"Kõne helitugevus"</string>
-    <string name="volume_icon_description_media" msgid="4997633254078171233">"Meediumi helitugevus"</string>
+    <string name="volume_icon_description_media" msgid="4997633254078171233">"Meedia helitugevus"</string>
     <string name="volume_icon_description_notification" msgid="579091344110747279">"Teatise helitugevus"</string>
     <string name="ringtone_default" msgid="9118299121288174597">"Vaikehelin"</string>
     <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Vaikimisi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6783b77..fb0ec66 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -596,9 +596,9 @@
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"لطفاً چهره‌تان را مجدداً ثبت کنید."</string>
     <string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
     <string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
-    <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی پایین آورید."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی پایین آورید."</string>
-    <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی پایین آورید."</string>
+    <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی صاف بگیرید."</string>
+    <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهره‌تان است بردارید."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
   <string-array name="face_acquired_vendor">
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 893433b..7dd89aa 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1593,7 +1593,7 @@
     <string name="kg_pattern_instructions" msgid="8366024510502517748">"Debuxa o teu padrón"</string>
     <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Introduce o PIN da tarxeta SIM"</string>
     <string name="kg_pin_instructions" msgid="7355933174673539021">"Introduce o PIN"</string>
-    <string name="kg_password_instructions" msgid="7179782578809398050">"Insire o teu contrasinal"</string>
+    <string name="kg_password_instructions" msgid="7179782578809398050">"Escribe o teu contrasinal"</string>
     <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"Agora a tarxeta SIM está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter información detallada."</string>
     <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Introduce o código PIN desexado"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirma o código PIN desexado"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f7f6214..6ace38d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -189,7 +189,7 @@
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"આ ઉપકરણ પર તમારી કાર્યાલયની પ્રોફાઇલ હવે ઉપલબ્ધ નથી"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"પાસવર્ડના ઘણા વધુ પ્રયત્નો"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"વ્યવસ્થાપકે ડિવાઇસ વ્યક્તિગત ઉપયોગ માટે આપી દીધું છે"</string>
-    <string name="network_logging_notification_title" msgid="554983187553845004">"ઉપકરણ સંચાલિત છે"</string>
+    <string name="network_logging_notification_title" msgid="554983187553845004">"ડિવાઇસ મેનેજ થયેલ છે"</string>
     <string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string>
     <string name="location_changed_notification_title" msgid="3620158742816699316">"ઍપ તમારા સ્થાનને ઍક્સેસ કરી શકે છે"</string>
     <string name="location_changed_notification_text" msgid="7158423339982706912">"વધુ જાણવા માટે તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો"</string>
@@ -314,7 +314,7 @@
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"કૉલ લૉગ"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"ફોન કૉલ લૉગ વાંચો અને લખો"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"ફોન"</string>
-    <string name="permgroupdesc_phone" msgid="270048070781478204">"ફોન કૉલ કરો અને સંચાલિત કરો"</string>
+    <string name="permgroupdesc_phone" msgid="270048070781478204">"ફોન કૉલ કરો અને મેનેજ કરો"</string>
     <string name="permgrouplab_sensors" msgid="9134046949784064495">"બૉડી સેન્સર"</string>
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"તમારા મહત્વપૂર્ણ ચિહ્નો વિશે સેન્સર ડેટા ઍક્સેસ કરો"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"વિંડો કન્ટેન્ટ પુનઃપ્રાપ્ત કરો"</string>
@@ -365,7 +365,7 @@
     <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"એપ્લિકેશનને WAP સંદેશા પ્રાપ્ત કરવાની અને તેના પર પ્રક્રિયા કરવાની મંજૂરી આપે છે. આ પરવાનગીમાં તમને દર્શાવ્યા વિના તમને મોકલેલ સંદેશાઓનું નિરીક્ષણ કરવાની અને કાઢી નાખવાની ક્ષમતાનો સમાવેશ થાય છે."</string>
     <string name="permlab_getTasks" msgid="7460048811831750262">"ચાલુ ઍપ્લિકેશનો પુનઃપ્રાપ્ત કરો"</string>
     <string name="permdesc_getTasks" msgid="7388138607018233726">"એપ્લિકેશનને વર્તમાનમાં અને તાજેતરમાં ચાલી રહેલ Tasks વિશેની વિગતવાર માહિતી પુનઃપ્રાપ્ત કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને ઉપકરણ પર કઈ એપ્લિકેશન્સનો ઉપયોગ થાય છે તેના વિશેની માહિતી શોધવાની મંજૂરી આપી શકે છે."</string>
-    <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"પ્રોફાઇલ અને ઉપકરણ માલિકોને સંચાલિત કરો"</string>
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"પ્રોફાઇલ અને ડિવાઇસ માલિકોને મેનેજ કરો"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"એપ્લિકેશન્સને પ્રોફાઇલ માલિકો અને ઉપકરણ માલિકો સેટ કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_reorderTasks" msgid="7598562301992923804">"ચાલુ એપ્લિકેશન્સને ફરી ગોઠવો"</string>
     <string name="permdesc_reorderTasks" msgid="8796089937352344183">"ઍપ્લિકેશનને અગ્રભૂમિ અને પૃષ્ટભૂમિમાં Tasks ખસેડવાની મંજૂરી આપે છે. તમારા ઇનપુટ વિના ઍપ્લિકેશન આ કરી શકે છે."</string>
@@ -530,7 +530,7 @@
     <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"ઍપને સ્ક્રીન લૉકની જટિલતાનું લેવલ (ઊંચું, મધ્યમ, નીચું અથવા કોઈ નહીં) જાણવાની મંજૂરી આપે છે, જે સ્ક્રીન લૉકના પ્રકાર અને લંબાઈની સંભવિત શ્રેણી સૂચવે છે. ઍપ વપરાશકર્તાઓને સ્ક્રીન લૉકને ચોક્કસ લેવલ સુધી અપડેટ કરવાનું સૂચન પણ કરી શકે છે, પરંતુ વપરાશકર્તાઓ મુક્ત રીતે અવગણીને નૅવિગેટ કરી શકે છે. નોંધી લો કે સ્ક્રીન લૉકનો plaintextમાં સંગ્રહ કરવામાં આવતો નથી, તેથી ઍપને ચોક્કસ પાસવર્ડની જાણ હોતી નથી."</string>
     <string name="permlab_useBiometric" msgid="6314741124749633786">"બાયોમેટ્રિક હાર્ડવેરનો ઉપયોગ કરો"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"ઍપને પ્રમાણીકરણ માટે બાયોમેટ્રિક હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
-    <string name="permlab_manageFingerprint" msgid="7432667156322821178">"ફિંગરપ્રિન્ટ હાર્ડવેરને સંચાલિત કરો"</string>
+    <string name="permlab_manageFingerprint" msgid="7432667156322821178">"ફિંગરપ્રિન્ટ હાર્ડવેરને મેનેજ કરો"</string>
     <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"ઍપને ઉપયોગ માટે ફિંગરપ્રિન્ટ નમૂના ઉમેરવા અને કાઢી નાખવા માટે પદ્ધતિઓની વિનંતી કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_useFingerprint" msgid="1001421069766751922">"ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરો"</string>
     <string name="permdesc_useFingerprint" msgid="412463055059323742">"ઍપને પ્રમાણીકરણ માટે ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
@@ -634,8 +634,8 @@
     <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"એપ્લિકેશનને નવા ટેલિકોમ સિમ કનેક્શન્સની નોંધણી કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_register_call_provider" msgid="6135073566140050702">"નવા ટેલિકોમ કનેક્શન્સની નોંધણી કરો"</string>
     <string name="permdesc_register_call_provider" msgid="4201429251459068613">"એપ્લિકેશનને નવા ટેલિકોમ કનેક્શન્સની નોંધણી કરવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_connection_manager" msgid="3179365584691166915">"ટેલિકોમ કનેક્શન્સ સંચાલિત કરો"</string>
-    <string name="permdesc_connection_manager" msgid="1426093604238937733">"એપ્લિકેશનને ટેલીકોમ કનેક્શન્સને સંચાલિત કરવાની મંજૂરી આપે છે."</string>
+    <string name="permlab_connection_manager" msgid="3179365584691166915">"ટેલિકોમ કનેક્શનને મેનેજ કરો"</string>
+    <string name="permdesc_connection_manager" msgid="1426093604238937733">"ઍપને ટેલિકોમ કનેક્શનને મેનેજ કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_bind_incall_service" msgid="5990625112603493016">"ઇન-કૉલ સ્ક્રીન વડે ક્રિયાપ્રતિક્રિયા કરો"</string>
     <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"વપરાશકર્તા ઇન-કૉલ સ્ર્કીન ક્યારે અને કેવી રીતે જુએ છે તે નિયંત્રિત કરવાની એપ્લિકેશનને મંજૂરી આપે છે."</string>
     <string name="permlab_bind_connection_service" msgid="5409268245525024736">"ટેલિફોની સેવાઓ સાથે વાર્તાલાપ કરો"</string>
@@ -644,8 +644,8 @@
     <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"એપ્લિકેશનને કૉલમાં વપરાશકર્તા અનુભવ પ્રદાન કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"ઐતિહાસિક નેટવર્ક ઉપયોગ વાંચો"</string>
     <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"એપ્લિકેશનને ચોક્કસ નેટવર્ક્સ અને ઍપ્લિકેશનો માટે ઐતિહાસિક નેટવર્ક વપરાશ વાંચવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"નેટવર્ક નીતિ સંચાલિત કરો"</string>
-    <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"ઍપ્લિકેશનને નેટવર્ક નીતિઓ સંચાલિત કરવાની અને ઍપ્લિકેશન-વિશિષ્ટ નિયમો નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
+    <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"નેટવર્ક નીતિ મેનેજ કરો"</string>
+    <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"ઍપને નેટવર્ક નીતિઓ મેનેજ કરવાની અને ઍપ-વિશિષ્ટ નિયમો નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"નેટવર્ક વપરાશ એકાઉન્ટિંગ સંશોધિત કરો"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"એપ્લિકેશનને કેવી રીતે ઍપ્લિકેશનો સામે નેટવર્ક વપરાશ ગણવામાં આવે છે તે સંશોધિત કરવાની મંજૂરી આપે છે. સામાન્ય ઍપ્લિકેશનો દ્વારા ઉપયોગમાં લેવા માટે નથી."</string>
     <string name="permlab_accessNotifications" msgid="7130360248191984741">"ઍક્સેસ સૂચનાઓ"</string>
@@ -1435,8 +1435,8 @@
     <string name="notification_ranker_binding_label" msgid="432708245635563763">"સૂચના રેંકર સેવા"</string>
     <string name="vpn_title" msgid="5906991595291514182">"VPN સક્રિય કર્યું"</string>
     <string name="vpn_title_long" msgid="6834144390504619998">"<xliff:g id="APP">%s</xliff:g> દ્વારા VPN સક્રિય થયું"</string>
-    <string name="vpn_text" msgid="2275388920267251078">"નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
-    <string name="vpn_text_long" msgid="278540576806169831">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
+    <string name="vpn_text" msgid="2275388920267251078">"નેટવર્કને મેનેજ કરવા માટે ટૅપ કરો."</string>
+    <string name="vpn_text_long" msgid="278540576806169831">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને મેનેજ કરવા માટે ટૅપ કરો."</string>
     <string name="vpn_lockdown_connecting" msgid="6096725311950342607">"હંમેશા-ચાલુ VPN કનેક્ટ થઈ રહ્યું છે…"</string>
     <string name="vpn_lockdown_connected" msgid="2853127976590658469">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
     <string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"હંમેશાં-ચાલુ VPN થી ડિસ્કનેક્ટ થયું"</string>
@@ -1911,7 +1911,7 @@
     <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g>ને પિન કરો"</string>
     <string name="unpin_target" msgid="3963318576590204447">"અનપિન કરો"</string>
     <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ને અનપિન કરો"</string>
-    <string name="app_info" msgid="6113278084877079851">"ઍપ્લિકેશન માહિતી"</string>
+    <string name="app_info" msgid="6113278084877079851">"ઍપની માહિતી"</string>
     <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="demo_starting_message" msgid="6577581216125805905">"ડેમો પ્રારંભ કરી રહ્યાં છે…"</string>
     <string name="demo_restarting_message" msgid="1160053183701746766">"ઉપકરણ ફરીથી સેટ કરી રહ્યાં છે…"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b1fe76e..a85ed70 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1228,7 +1228,7 @@
     <string name="volume_music" msgid="7727274216734955095">"Մեդիա ձայնի բարձրություն"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Նվագարկում է Bluetooth-ի միջոցով"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Սահմանվել է անձայն զանգերանգ"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Մուտքային զանգի ձայնի ուժգնությունը"</string>
+    <string name="volume_call" msgid="7625321655265747433">"Խոսակցություն"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth-ի ներզանգի բարձրություն"</string>
     <string name="volume_alarm" msgid="4486241060751798448">"Զարթուցիչի ձայնը"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Ծանուցումների ձայնի ուժգնությունը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index cc8071b..cbcb131 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1228,7 +1228,7 @@
     <string name="volume_music" msgid="7727274216734955095">"Volume media"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Memutar melalui Bluetooth"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Nada dering senyap disetel"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Volume saat-memanggil"</string>
+    <string name="volume_call" msgid="7625321655265747433">"Volume dalam panggilan"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volume saat-memanggil bluetooth"</string>
     <string name="volume_alarm" msgid="4486241060751798448">"Volume alarm"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Volume pemberitahuan"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 093daf1..3139dce 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -61,7 +61,7 @@
     <string name="ColpMmi" msgid="4736462893284419302">"Қосылған желі идентификаторы"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Қосылған желі идентификаторын шектеу"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Қоңырауды басқа нөмірге бағыттау"</string>
-    <string name="CwMmi" msgid="3164609577675404761">"Күтудегі қоңырау"</string>
+    <string name="CwMmi" msgid="3164609577675404761">"Қоңырауды ұстап тұру"</string>
     <string name="BaMmi" msgid="7205614070543372167">"Қоңырауды бөгеу"</string>
     <string name="PwdMmi" msgid="3360991257288638281">"Құпия сөз өзгерту"</string>
     <string name="PinMmi" msgid="7133542099618330959">"PIN өзгерту"</string>
@@ -1228,9 +1228,9 @@
     <string name="volume_music" msgid="7727274216734955095">"Mультимeдиа дыбыс деңгейі"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth арқылы ойнату"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Үнсіз қоңырау әуенін орнату"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Келетін қоңырау дыбысының қаттылығы"</string>
+    <string name="volume_call" msgid="7625321655265747433">"Сөйлесу кезіндегі дыбыс деңгейі"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth қоңырауының қаттылығы"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"Дабыл дыбысының қаттылығы"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"Дабыл дыбысының деңгейі"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Хабар дыбысының қаттылығы"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"Дыбыс қаттылығы"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetooth дыбысының қаттылығы"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 53c92af..cc7c72a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1228,8 +1228,8 @@
     <string name="volume_music" msgid="7727274216734955095">"កម្រិត​សំឡេង​មេឌៀ"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"ចាក់​តាម​ប៊្លូធូស"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"កំណត់​សំឡេង​រោទ៍​ស្ងាត់"</string>
-    <string name="volume_call" msgid="7625321655265747433">"កម្រិត​សំឡេង​ហៅ​ចូល"</string>
-    <string name="volume_bluetooth_call" msgid="2930204618610115061">"កម្រិត​សំឡេង​ហៅ​ចូល​តាម​ប៊្លូធូស"</string>
+    <string name="volume_call" msgid="7625321655265747433">"កម្រិត​សំឡេង​ក្នុងពេលនិយាយទូរសព្ទ"</string>
+    <string name="volume_bluetooth_call" msgid="2930204618610115061">"កម្រិត​សំឡេង​ក្នុងពេលនិយាយទូរសព្ទ​តាម​ប៊្លូធូស"</string>
     <string name="volume_alarm" msgid="4486241060751798448">"កម្រិត​សំឡេងម៉ោងរោទ៍"</string>
     <string name="volume_notification" msgid="6864412249031660057">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"កម្រិត​សំឡេង"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 811973b..d3a3148 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1230,7 +1230,7 @@
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"ಶಾಂತ ರಿಂಗ್‌ಟೋನ್ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
     <string name="volume_call" msgid="7625321655265747433">"ಒಳ-ಕರೆಯ ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"ಬ್ಲೂಟೂತ್‌‌ ಒಳ-ಕರೆಯ ವಾಲ್ಯೂಮ್"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"ಅಲಾರಮ್ ವಾಲ್ಯೂಮ್"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"ಅಲಾರಂ ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_notification" msgid="6864412249031660057">"ಅಧಿಸೂಚನೆಯ ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"ವಾಲ್ಯೂಮ್"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"ಬ್ಲೂಟೂತ್‌‌ ವಾಲ್ಯೂಮ್"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index b2e2c1d..9e2e0a2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -864,12 +864,12 @@
     <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Колдонуучунун нускамасын караңыз же Кардарларды тейлөө борборуна кайрылыңыз."</string>
     <string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"SIM-карта бөгөттөлгөн."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"SIM-карта бөгөттөн чыгарылууда…"</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Графикалык ачкычыңызды <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес чийдиңиз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүздүн кулпусун Google аккаунтуңузга кирип ачышыңыз керек болот.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайталап көрүңүз."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Сиз планшетиңизди бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүз демейки жөндөөлөргө кайтарылып, бардык колдонуучу дайындары жоголот."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Сиз телефонуңузду бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string>
@@ -1228,7 +1228,7 @@
     <string name="volume_music" msgid="7727274216734955095">"Мультимедианын катуулугу"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth аркылуу ойнотулууда"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Үнсүз рингтон орнотулду"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Чалуудагы үн көлөмү"</string>
+    <string name="volume_call" msgid="7625321655265747433">"Сүйлөшүүнүн катуулугу"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth чалуудагы үн көлөмү"</string>
     <string name="volume_alarm" msgid="4486241060751798448">"Ойготкучтун катуулугу"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Эскертме үн көлөмү"</string>
diff --git a/core/res/res/values-mcc311-mnc180-as/strings.xml b/core/res/res/values-mcc311-mnc180-as/strings.xml
deleted file mode 100644
index daa090c..0000000
--- a/core/res/res/values-mcc311-mnc180-as/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"ছিমখন প্ৰ\'ভিজন কৰা হোৱা নাই MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"ছিমৰ অনুমতি নাই MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ফ\'নৰ অনুমতি নাই MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-az/strings.xml b/core/res/res/values-mcc311-mnc180-az/strings.xml
deleted file mode 100644
index 7b8bd89..0000000
--- a/core/res/res/values-mcc311-mnc180-az/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM MM#2 təmin etmir"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM MM#3 dəstəkləmir"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"MM#6 telefonu dəstəklənmir"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml b/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml
deleted file mode 100644
index 6cbc6ee..0000000
--- a/core/res/res/values-mcc311-mnc180-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM kartica nije podešena MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM kartica nije dozvoljena MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Telefon nije dozvoljen MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-be/strings.xml b/core/res/res/values-mcc311-mnc180-be/strings.xml
deleted file mode 100644
index 363bcde..0000000
--- a/core/res/res/values-mcc311-mnc180-be/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM-карты няма MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM-карта не дапускаецца MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Тэлефон не дапускаецца MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-bn/strings.xml b/core/res/res/values-mcc311-mnc180-bn/strings.xml
deleted file mode 100644
index 23b9fdf..0000000
--- a/core/res/res/values-mcc311-mnc180-bn/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"সিমের জন্য প্রস্তুত নয় MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"সিমের অনুমতি নেই MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ফোন অনুমোদিত নয় MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-bs/strings.xml b/core/res/res/values-mcc311-mnc180-bs/strings.xml
deleted file mode 100644
index c73e0dc..0000000
--- a/core/res/res/values-mcc311-mnc180-bs/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM kartica nije dodijeljena MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM kartica nije dozvoljena MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Telefon nije dozvoljen MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml b/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml
deleted file mode 100644
index bd58d57..0000000
--- a/core/res/res/values-mcc311-mnc180-en-rAU/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM not provisioned MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM not allowed MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Phone not allowed MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml b/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml
deleted file mode 100644
index bd58d57..0000000
--- a/core/res/res/values-mcc311-mnc180-en-rCA/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM not provisioned MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM not allowed MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Phone not allowed MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml b/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml
deleted file mode 100644
index a9fdf61..0000000
--- a/core/res/res/values-mcc311-mnc180-en-rXC/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‎SIM not provisioned MM#2‎‏‎‎‏‎"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎SIM not allowed MM#3‎‏‎‎‏‎"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎Phone not allowed MM#6‎‏‎‎‏‎"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-gu/strings.xml b/core/res/res/values-mcc311-mnc180-gu/strings.xml
deleted file mode 100644
index 26f735b..0000000
--- a/core/res/res/values-mcc311-mnc180-gu/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIMને MM#2ની જોગવાઈ નથી"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIMને MM#3 કરવાની મંજૂરી નથી"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"MM#6 ફોનની મંજૂરી નથી"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-kk/strings.xml b/core/res/res/values-mcc311-mnc180-kk/strings.xml
deleted file mode 100644
index 18c492d..0000000
--- a/core/res/res/values-mcc311-mnc180-kk/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM картасы қарастырылмаған MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM картасына рұқсат етілмеген MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Телефон пайдалануға болмайды MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-kn/strings.xml b/core/res/res/values-mcc311-mnc180-kn/strings.xml
deleted file mode 100644
index 6de3655..0000000
--- a/core/res/res/values-mcc311-mnc180-kn/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"MM#2 ಗೆ ಸಿಮ್‌ ಸಿದ್ಧವಾಗಿಲ್ಲ"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"ಸಿಮ್‌ MM#3 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ಫೋನ್ MM#6 ಅನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-or/strings.xml b/core/res/res/values-mcc311-mnc180-or/strings.xml
deleted file mode 100644
index 8b2ffd9..0000000
--- a/core/res/res/values-mcc311-mnc180-or/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM କାର୍ଡ ପ୍ରସ୍ତୁତ କରାଯାଇନାହିଁ MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM କାର୍ଡର ଅନୁମତି ନାହିଁ MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ଫୋନ୍‌ର ଅନୁମତି ନାହିଁ MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-pa/strings.xml b/core/res/res/values-mcc311-mnc180-pa/strings.xml
deleted file mode 100644
index b716a2e..0000000
--- a/core/res/res/values-mcc311-mnc180-pa/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"ਸਿਮ ਦੀ ਵਿਵਸਥਾ ਨਹੀਂ ਹੈ MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"ਸਿਮ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ਫ਼ੋਨ ਨੂੰ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml b/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
deleted file mode 100644
index 6788df9..0000000
--- a/core/res/res/values-mcc311-mnc180-pt-rBR/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"Chip não aprovisionado MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"Chip não permitido MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Smartphone não permitido MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-sq/strings.xml b/core/res/res/values-mcc311-mnc180-sq/strings.xml
deleted file mode 100644
index eeec051..0000000
--- a/core/res/res/values-mcc311-mnc180-sq/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"Karta SIM nuk është dhënë MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"Karta SIM nuk lejohet MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Telefoni nuk lejohet MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-ta/strings.xml b/core/res/res/values-mcc311-mnc180-ta/strings.xml
deleted file mode 100644
index 5a9f97b..0000000
--- a/core/res/res/values-mcc311-mnc180-ta/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"சிம் அமைக்கப்படவில்லை MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"சிம் அனுமதிக்கப்படவில்லை MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ஃபோன் அனுமதிக்கப்படவில்லை MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-te/strings.xml b/core/res/res/values-mcc311-mnc180-te/strings.xml
deleted file mode 100644
index 7368dae3..0000000
--- a/core/res/res/values-mcc311-mnc180-te/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM MM#2ని సక్రియం చేయలేదు"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM MM#3ని అనుమతించలేదు"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"ఫోన్ అనుమతించబడదు MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-ur/strings.xml b/core/res/res/values-mcc311-mnc180-ur/strings.xml
deleted file mode 100644
index 57695ec..0000000
--- a/core/res/res/values-mcc311-mnc180-ur/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"‏SIM فراہم کردہ نہیں ہے MM#2"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"‏SIM کی اجازت نہیں ہے MM#3"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"‏فون کی اجازت نہیں ہے MM#6"</string>
-</resources>
diff --git a/core/res/res/values-mcc311-mnc180-uz/strings.xml b/core/res/res/values-mcc311-mnc180-uz/strings.xml
deleted file mode 100644
index bb1f84a..0000000
--- a/core/res/res/values-mcc311-mnc180-uz/strings.xml
+++ /dev/null
@@ -1,26 +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_imsi_unknown_in_hlr" msgid="604133804161351810">"SIM karta ishlatish taqiqlangan (MM#2)"</string>
-    <string name="mmcc_illegal_ms" msgid="4073997279280371621">"SIM karta ishlatish taqiqlangan (MM#3)"</string>
-    <string name="mmcc_illegal_me" msgid="4936539345546223576">"Chaqiruvlar taqiqlangan (MM#6)"</string>
-</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index bbcfc63..6523784 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -275,7 +275,7 @@
     <string name="notification_channel_car_mode" msgid="2123919247040988436">"Машины горим"</string>
     <string name="notification_channel_account" msgid="6436294521740148173">"Бүртгэлийн төлөв"</string>
     <string name="notification_channel_developer" msgid="1691059964407549150">"Хөгжүүлэгчийн мессеж"</string>
-    <string name="notification_channel_developer_important" msgid="7197281908918789589">"Хөгжүүлэгчийн чухал зурвас"</string>
+    <string name="notification_channel_developer_important" msgid="7197281908918789589">"Хөгжүүлэгчийн чухал мессеж"</string>
     <string name="notification_channel_updates" msgid="7907863984825495278">"Шинэчлэлтүүд"</string>
     <string name="notification_channel_network_status" msgid="2127687368725272809">"Сүлжээний төлөв"</string>
     <string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сүлжээний сануулга"</string>
@@ -358,9 +358,9 @@
     <string name="permlab_sendSms" msgid="7757368721742014252">"SMS мессежийг илгээх, харах"</string>
     <string name="permdesc_sendSms" msgid="6757089798435130769">"Апп нь SMS мессеж илгээх боломжтой. Энэ нь санаандгүй төлбөрт оруулж болзошгүй. Хортой апп нь таны зөвшөөрөлгүйгээр мессеж илгээн таныг төлбөрт оруулж болзошгүй."</string>
     <string name="permlab_readSms" msgid="5164176626258800297">"таны текст мессежийг унших(SMS эсвэл MMS)"</string>
-    <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Энэ апп таны таблетад хадгалсан бүх SMS (текст) зурвасыг унших боломжтой."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Энэ апп таны таблетад хадгалсан бүх SMS (текст) мессежийг унших боломжтой."</string>
     <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Энэ апп таны Android TV төхөөрөмжид хадгалсан бүх SMS (текст) мессежийг уншиж чадна."</string>
-    <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Энэ апп таны утсанд хадгалсан бүх SMS (текст) зурвасыг унших боломжтой."</string>
+    <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Энэ апп таны утсанд хадгалсан бүх SMS (текст) мессежийг унших боломжтой."</string>
     <string name="permlab_receiveWapPush" msgid="4223747702856929056">"текст мессеж(WAP) хүлээн авах"</string>
     <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Апп нь WAP мессежийг хүлээн авах болон биелүүлэх боломжтой. Энэ зөвшөөрөл нь танд илгээсэн мессежийг танд харуулалгүйгээр хянах эсвэл устгах боломжийг агуулна."</string>
     <string name="permlab_getTasks" msgid="7460048811831750262">"ажиллаж байгаа апп-г дуудах"</string>
@@ -418,9 +418,9 @@
     <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Энэ апп таны Android TV төхөөрөмжид хадгалсан календарийн бүх арга хэмжээг унших болон таны календарийн өгөгдлийг хуваалцах эсвэл хадгалах боломжтой."</string>
     <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Энэ апп таны утсанд хадгалсан хуанлийн бүх арга хэмжээг унших, хуанлийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
     <string name="permlab_writeCalendar" msgid="6422137308329578076">"календарын хуваарийг нэмэх эсвэл өөрчлөх болон эзэмшигчид мэдэгдэлгүйгээр зочидруу имэйл илгээх"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс зурвас илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Энэ апп таны Android TV төхөөрөмжид календарийн арга хэмжээ нэмэх, үүнийг устгах, эсвэл өөрчлөх боломжтой. Энэ апп календарийн өмчлөгчөөс ирсэн мэт харагдаж болох мессеж илгээх эсвэл арга хэмжээг өмчлөгчид нь мэдэгдэлгүйгээр өөрчлөх боломжтой."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс зурвас илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"байршил нийлүүлэгчийн нэмэлт тушаалд хандах"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Апп нь байршил нийлүүлэгчийн нэмэлт тушаалд хандах боломжтой. Энэ нь апп-д GPS эсвэл бусад байршлын үйлчилгээний ажиллагаанд нөлөөлөх боломжийг олгоно."</string>
     <string name="permlab_accessFineLocation" msgid="6426318438195622966">"нарийвчилсан байршилд зөвхөн нүүр хэсэгт хандах"</string>
@@ -668,8 +668,8 @@
     <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Одоогийн Андройд Бийм дамжуулалтын мэдээллийг хүлээн авахыг аппликейшнд зөвшөөрөх"</string>
     <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM сертификатыг устгах"</string>
     <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Аппликейшнд DRM сертификатыг устгахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
-    <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"зөөгч зурвасын үйлчилгээнд холбох"</string>
-    <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Эзэмшигчид зөөгч зурвасын үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
+    <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"зөөгч мессежийн үйлчилгээнд холбох"</string>
+    <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Эзэмшигчид зөөгч мессежийн үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"Үүрэн холбооны үйлчилгээ үзүүлэгчтэй холбогдох"</string>
     <string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Аливаа эзэмшигчийг үүрэн холбооны үйлчилгээ үзүүлэгчтэй холбодог. Энгийн аппд шаардлагагүй."</string>
     <string name="permlab_access_notification_policy" msgid="5524112842876975537">"Бүү саад бол тохируулгад хандалт хийх"</string>
@@ -966,7 +966,7 @@
     <string name="permlab_setAlarm" msgid="1158001610254173567">"сэрүүлэг тохируулах"</string>
     <string name="permdesc_setAlarm" msgid="2185033720060109640">"Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй."</string>
     <string name="permlab_addVoicemail" msgid="4770245808840814471">"дуут шуудан нэмэх"</string>
-    <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх."</string>
+    <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Таны дуут шуудангийн ирсэн мэйлд мессеж нэмэхийг апп-д зөвшөөрөх."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
     <string name="save_password_message" msgid="2146409467245462965">"Та хөтчид энэ нууц үгийг сануулах уу?"</string>
@@ -1900,7 +1900,7 @@
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Энэ аппыг Андройдын хуучин хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Шинэчлэлтийг шалгаж эсвэл хөгжүүлэгчтэй холбогдоно уу."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шинэчлэлтийг шалгах"</string>
-    <string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ зурвасууд байна"</string>
+    <string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ мессежүүд байна"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"Үзэхийн тулд SMS аппыг нээх"</string>
     <string name="profile_encrypted_title" msgid="9001208667521266472">"Зарим функцийг хязгаарласан байж болзошгүй"</string>
     <string name="profile_encrypted_detail" msgid="5279730442756849055">"Ажлын профайлыг түгжсэн"</string>
@@ -1968,7 +1968,7 @@
     <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
     <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"Эргийн бүс, голын эргийн бүсээс өндөрлөг газар зэрэг аюулгүй газар руу нэн даруй шилжинэ үү."</string>
     <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
-    <string name="etws_primary_default_message_test" msgid="4583367373909549421">"Онцгой байдлын зурвасын тест"</string>
+    <string name="etws_primary_default_message_test" msgid="4583367373909549421">"Онцгой байдлын мессежийн тест"</string>
     <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"Хариу бичих"</string>
     <string name="etws_primary_default_message_others" msgid="7958161706019130739"></string>
     <string name="mmcc_authentication_reject" msgid="4891965994643876369">"SIM-г дуу хоолойд зөвшөөрдөггүй"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 1dec3f9..11559f3 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1225,18 +1225,18 @@
     <string name="dump_heap_ready_text" msgid="5849618132123045516">"ਸਾਂਝਾ ਕਰਨ ਲਈ <xliff:g id="PROC">%1$s</xliff:g> ਦੀ ਪ੍ਰਕਿਰਿਆ ਦਾ ਹੀਪ ਡੰਪ ਤੁਹਾਡੇ ਲਈ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਸ਼ਾਇਦ ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਕੋਈ ਵੀ ਸੰਵੇਦਨਸ਼ੀਲ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋਵੇ, ਜਿਸ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਦੀ ਪਹੁੰਚ ਹੈ, ਜਿਸ ਵਿੱਚ ਸ਼ਾਇਦ ਤੁਹਾਡੇ ਵੱਲੋਂ ਟਾਈਪ ਕੀਤੀਆਂ ਚੀਜ਼ਾਂ ਸ਼ਾਮਲ ਹੋਣ।"</string>
     <string name="sendText" msgid="493003724401350724">"ਲਿਖਤ ਲਈ ਕੋਈ ਕਾਰਵਾਈ ਚੁਣੋ"</string>
     <string name="volume_ringtone" msgid="134784084629229029">"ਰਿੰਗਰ ਵੌਲਿਊਮ"</string>
-    <string name="volume_music" msgid="7727274216734955095">"ਮੀਡੀਆ ਵੌਲਿਊਮ"</string>
+    <string name="volume_music" msgid="7727274216734955095">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth ਰਾਹੀਂ ਪਲੇ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"ਖਾਮੋਸ਼ ਰਿੰਗਟੋਨ ਸੈੱਟ ਕੀਤੀ"</string>
     <string name="volume_call" msgid="7625321655265747433">"ਇਨ-ਕਾਲ ਅਵਾਜ਼"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"ਬਲੂਟੁੱਥ ਇਨ-ਕਾਲ ਅਵਾਜ਼"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"ਅਲਾਰਮ ਵੌਲਿਊਮ"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"ਅਲਾਰਮ ਦੀ ਅਵਾਜ਼"</string>
     <string name="volume_notification" msgid="6864412249031660057">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"ਵੌਲਿਊਮ"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetooth ਵੌਲਿਊਮ"</string>
     <string name="volume_icon_description_ringer" msgid="2187800636867423459">"ਰਿੰਗਟੋਨ ਵੌਲਿਊਮ"</string>
     <string name="volume_icon_description_incall" msgid="4491255105381227919">"ਕਾਲ ਅਵਾਜ਼"</string>
-    <string name="volume_icon_description_media" msgid="4997633254078171233">"ਮੀਡੀਆ ਵੌਲਿਊਮ"</string>
+    <string name="volume_icon_description_media" msgid="4997633254078171233">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</string>
     <string name="volume_icon_description_notification" msgid="579091344110747279">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</string>
     <string name="ringtone_default" msgid="9118299121288174597">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰਿੰਗਟੋਨ"</string>
     <string name="ringtone_default_with_actual" msgid="2709686194556159773">"ਪੂਰਵ-ਨਿਰਧਾਰਤ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3a8b28b..35bf873 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1270,7 +1270,7 @@
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Выбран режим \"Без звука\""</string>
     <string name="volume_call" msgid="7625321655265747433">"Громкость при разговоре"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Громкость при разговоре"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"Громкость сигнала предупреждения"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"Громкость будильника"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Громкость уведомления"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"Громкость"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Громкость Bluetooth-устройства"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9124c12..1ca8fb8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -307,7 +307,7 @@
     <string name="permgroupdesc_storage" msgid="6351503740613026600">"ifikie picha, maudhui na faili kwenye kifaa chako"</string>
     <string name="permgrouplab_microphone" msgid="2480597427667420076">"Maikrofoni"</string>
     <string name="permgroupdesc_microphone" msgid="1047786732792487722">"irekodi sauti"</string>
-    <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Shughuli za kimwili"</string>
+    <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Mazoezi ya mwili"</string>
     <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ifikie shughuli zako za kimwili"</string>
     <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"ipige picha na kurekodi video"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6a15ffc..4112fa5 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1798,8 +1798,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
-    <string name="battery_saver_description" msgid="6794188153647295212">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
+    <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para patagalin ang baterya, ginagawa ng Pantipid ng Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+    <string name="battery_saver_description" msgid="6794188153647295212">"Para patagalin ang baterya, ginagawa ng Pantipid ng Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string>
@@ -2007,9 +2007,9 @@
     <string name="notification_feedback_indicator" msgid="663476517711323016">"Magbigay ng Feedback"</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string>
     <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string>
-    <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pangtipid sa Baterya para patagalin ang buhay ng baterya"</string>
-    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pangtipid sa Baterya"</string>
-    <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pangtipid sa Baterya"</string>
+    <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pantipid ng Baterya para patagalin ang buhay ng baterya"</string>
+    <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pantipid ng Baterya"</string>
+    <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pantipid ng Baterya"</string>
     <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"May sapat na charge ang telepono. Hindi na pinaghihigpitan ang mga feature."</string>
     <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"May sapat na charge ang tablet. Hindi na pinaghihigpitan ang mga feature."</string>
     <string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"May sapat na charge ang device. Hindi na pinaghihigpitan ang mga feature."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5ad2ea1..778e4a5 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1268,9 +1268,9 @@
     <string name="volume_music" msgid="7727274216734955095">"Гучність медіа"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Відтвор. через Bluetooth"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Установлено сигнал дзвінка без звуку"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Обсяг вхідних"</string>
-    <string name="volume_bluetooth_call" msgid="2930204618610115061">"Обсяг вхідних Bluetooth"</string>
-    <string name="volume_alarm" msgid="4486241060751798448">"Гучн. сповіщ."</string>
+    <string name="volume_call" msgid="7625321655265747433">"Гучність під час розмови"</string>
+    <string name="volume_bluetooth_call" msgid="2930204618610115061">"Гучність у викликах Bluetooth"</string>
+    <string name="volume_alarm" msgid="4486241060751798448">"Гучність будильника"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Гучність сповіщень"</string>
     <string name="volume_unknown" msgid="4041914008166576293">"Гучність"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Гучність Bluetooth"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 229e225..683a911 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1228,7 +1228,7 @@
     <string name="volume_music" msgid="7727274216734955095">"Multimedia tovushi"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth orqali ijro etilmoqda"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Ovozsiz rejim tanlandi"</string>
-    <string name="volume_call" msgid="7625321655265747433">"Suhbat vaqtidagi tovush balandligi"</string>
+    <string name="volume_call" msgid="7625321655265747433">"Suhbat tovushi"</string>
     <string name="volume_bluetooth_call" msgid="2930204618610115061">"Kiruvchi bluetooth tovushi"</string>
     <string name="volume_alarm" msgid="4486241060751798448">"Signal tovushi"</string>
     <string name="volume_notification" msgid="6864412249031660057">"Eslatma tovushi"</string>
@@ -1240,7 +1240,7 @@
     <string name="volume_icon_description_notification" msgid="579091344110747279">"Eslatma tovushi"</string>
     <string name="ringtone_default" msgid="9118299121288174597">"Standart rington"</string>
     <string name="ringtone_default_with_actual" msgid="2709686194556159773">"Standart (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="397111123930141876">"Yo‘q"</string>
+    <string name="ringtone_silent" msgid="397111123930141876">"Hech qanday"</string>
     <string name="ringtone_picker_title" msgid="667342618626068253">"Ringtonlar"</string>
     <string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Signal ovozlari"</string>
     <string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Bildirishnoma ovozlari"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 082397e..433a46b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1695,6 +1695,13 @@
         <item>com.android.location.fused</item>
     </string-array>
 
+    <!-- Gnss Psds Servers -->
+    <string name="config_longterm_psds_server_1" translatable="false"></string>
+    <string name="config_longterm_psds_server_2" translatable="false"></string>
+    <string name="config_longterm_psds_server_3" translatable="false"></string>
+    <string name="config_normal_psds_server" translatable="false"></string>
+    <string name="config_realtime_psds_server" translatable="false"></string>
+
     <!-- This string array can be overriden to enable test location providers initially. -->
     <!-- Array of "[locationProviderName],[requiresNetwork],
          [requiresSatellite],[requiresCell],[hasMonetaryCost],
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4e4e3f8..6960fb34 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1861,6 +1861,11 @@
   <java-symbol type="array" name="config_locationProviderPackageNames" />
   <java-symbol type="array" name="config_locationExtraPackageNames" />
   <java-symbol type="array" name="config_testLocationProviders" />
+  <java-symbol type="string" name="config_longterm_psds_server_1" />
+  <java-symbol type="string" name="config_longterm_psds_server_2" />
+  <java-symbol type="string" name="config_longterm_psds_server_3" />
+  <java-symbol type="string" name="config_normal_psds_server" />
+  <java-symbol type="string" name="config_realtime_psds_server" />
   <java-symbol type="array" name="config_defaultNotificationVibePattern" />
   <java-symbol type="array" name="config_notificationFallbackVibePattern" />
   <java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" />
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 9246a23..f4a454b 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -311,6 +311,7 @@
         final File f = File.createTempFile(prefix, extension);
         f.setReadable(true, true);
         f.setWritable(true, true);
+
         f.deleteOnExit();
         return f;
     }
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 400b05c0..4fe68cd 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -73,6 +73,7 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
 
 /**
  * Test for verifying {@link android.app.ActivityThread} class.
@@ -173,29 +174,41 @@
 
     @Test
     public void testHandleActivity_assetsChanged() {
+        relaunchActivityAndAssertPreserveWindow(activity -> {
+            // Relaunches all activities.
+            activity.getActivityThread().handleApplicationInfoChanged(
+                    activity.getApplicationInfo());
+        });
+    }
+
+    @Test
+    public void testRecreateActivity() {
+        relaunchActivityAndAssertPreserveWindow(Activity::recreate);
+    }
+
+    private void relaunchActivityAndAssertPreserveWindow(Consumer<Activity> relaunch) {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+        final ActivityThread activityThread = activity.getActivityThread();
 
         final IBinder[] token = new IBinder[1];
         final View[] decorView = new View[1];
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            final ActivityThread activityThread = activity.getActivityThread();
-
             token[0] = activity.getActivityToken();
             decorView[0] = activity.getWindow().getDecorView();
 
-            // Relaunches all activities
-            activityThread.handleApplicationInfoChanged(activity.getApplicationInfo());
+            relaunch.accept(activity);
         });
 
         final View[] newDecorView = new View[1];
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            final ActivityThread activityThread = activity.getActivityThread();
+        final Activity[] newActivity = new Activity[1];
 
-            final Activity newActivity = activityThread.getActivity(token[0]);
-            newDecorView[0] = activity.getWindow().getDecorView();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            newActivity[0] = activityThread.getActivity(token[0]);
+            newDecorView[0] = newActivity[0].getWindow().getDecorView();
         });
 
+        assertNotEquals("Activity must be relaunched", activity, newActivity[0]);
         assertEquals("Window must be preserved", decorView[0], newDecorView[0]);
     }
 
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 2d16f82..cfed2ce 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -17,6 +17,7 @@
 package android.graphics;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
@@ -34,6 +35,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Random;
 
 @RunWith(AndroidJUnit4.class)
@@ -171,4 +175,27 @@
 
     }
 
+    @SmallTest
+    @Test
+    public void testSerialize() throws Exception {
+        int size = Typeface.writeTypefaces(null, Arrays.asList(mFaces));
+        ByteBuffer buffer = ByteBuffer.allocateDirect(size);
+        Typeface.writeTypefaces(buffer, Arrays.asList(mFaces));
+        List<Typeface> copiedTypefaces = Typeface.readTypefaces(buffer);
+        assertNotNull(copiedTypefaces);
+        assertEquals(mFaces.length, copiedTypefaces.size());
+        for (int i = 0; i < mFaces.length; i++) {
+            Typeface original = mFaces[i];
+            Typeface copied = copiedTypefaces.get(i);
+            assertEquals(original.getStyle(), copied.getStyle());
+            assertEquals(original.getWeight(), copied.getWeight());
+            assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+        }
+    }
+
+    private static float measureText(Typeface typeface, String text) {
+        Paint paint = new Paint();
+        paint.setTypeface(typeface);
+        return paint.measureText(text);
+    }
 }
diff --git a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
index 1947c6c..6955ca8 100644
--- a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
@@ -84,13 +84,6 @@
                 () -> CombinedVibrationEffect.startSequential()
                         .addNext(0, INVALID_EFFECT)
                         .combine());
-        assertThrows(IllegalArgumentException.class,
-                () -> new CombinedVibrationEffect.Sequential(
-                        Arrays.asList(CombinedVibrationEffect.startSequential()
-                                .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
-                                .combine()),
-                        Arrays.asList(0))
-                        .validate());
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
new file mode 100644
index 0000000..be63a0e
--- /dev/null
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util;
+
+import static android.util.XmlTest.assertNext;
+import static android.util.XmlTest.buildPersistableBundle;
+import static android.util.XmlTest.doPersistableBundleRead;
+import static android.util.XmlTest.doPersistableBundleWrite;
+
+import static org.junit.Assert.assertEquals;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.os.PersistableBundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+@RunWith(AndroidJUnit4.class)
+public class BinaryXmlTest {
+    /**
+     * Verify that we can write and read large numbers of interned
+     * {@link String} values.
+     */
+    @Test
+    public void testLargeInterned_Binary() throws Exception {
+        // We're okay with the tag itself being interned
+        final int count = (1 << 16) - 2;
+
+        final TypedXmlSerializer out = Xml.newBinarySerializer();
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        out.setOutput(os, StandardCharsets.UTF_8.name());
+        out.startTag(null, "tag");
+        for (int i = 0; i < count; i++) {
+            out.attribute(null, "name" + i, "value");
+        }
+        out.endTag(null, "tag");
+        out.flush();
+
+        final TypedXmlPullParser in = Xml.newBinaryPullParser();
+        final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+        in.setInput(is, StandardCharsets.UTF_8.name());
+        assertNext(in, START_TAG, "tag", 1);
+        assertEquals(count, in.getAttributeCount());
+    }
+
+    @Test
+    public void testTranscode_FastToBinary() throws Exception {
+        doTranscode(Xml.newFastSerializer(), Xml.newFastPullParser(),
+                Xml.newBinarySerializer(), Xml.newBinaryPullParser());
+    }
+
+    @Test
+    public void testTranscode_BinaryToFast() throws Exception {
+        doTranscode(Xml.newBinarySerializer(), Xml.newBinaryPullParser(),
+                Xml.newFastSerializer(), Xml.newFastPullParser());
+    }
+
+    /**
+     * Verify that a complex {@link PersistableBundle} can be transcoded using
+     * the two given formats with the original structure intact.
+     */
+    private static void doTranscode(TypedXmlSerializer firstOut, TypedXmlPullParser firstIn,
+            TypedXmlSerializer secondOut, TypedXmlPullParser secondIn) throws Exception {
+        final PersistableBundle expected = buildPersistableBundle();
+        final byte[] firstRaw = doPersistableBundleWrite(firstOut, expected);
+
+        // Perform actual transcoding between the two formats
+        final ByteArrayInputStream is = new ByteArrayInputStream(firstRaw);
+        firstIn.setInput(is, StandardCharsets.UTF_8.name());
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        secondOut.setOutput(os, StandardCharsets.UTF_8.name());
+        Xml.copy(firstIn, secondOut);
+
+        // Yes, this string-based check is fragile, but kindofEquals() is broken
+        // when working with nested objects and arrays
+        final PersistableBundle actual = doPersistableBundleRead(secondIn, os.toByteArray());
+        assertEquals(expected.toString(), actual.toString());
+    }
+}
diff --git a/core/tests/coretests/src/android/util/CharsetUtilsTest.java b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
new file mode 100644
index 0000000..04cb3d7
--- /dev/null
+++ b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CharsetUtilsTest {
+    private byte[] dest;
+    private long destPtr;
+
+    @Before
+    public void setUp() {
+        dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 8);
+        destPtr = VMRuntime.getRuntime().addressOf(dest);
+    }
+
+    @Test
+    public void testUtf8_Empty() {
+        assertEquals(0, CharsetUtils.toUtf8Bytes("", destPtr, 0, dest.length));
+        assertEquals("0000000000000000", HexDump.toHexString(dest));
+    }
+
+    @Test
+    public void testUtf8_Simple() {
+        assertEquals(7, CharsetUtils.toUtf8Bytes("example", destPtr, 0, dest.length));
+        assertEquals("6578616D706C6500", HexDump.toHexString(dest));
+    }
+
+    @Test
+    public void testUtf8_Complex() {
+        assertEquals(3, CharsetUtils.toUtf8Bytes("☃", destPtr, 4, dest.length));
+        assertEquals("00000000E2988300", HexDump.toHexString(dest));
+    }
+
+    @Test
+    public void testUtf8_Bounds() {
+        assertEquals(-1, CharsetUtils.toUtf8Bytes("foo", destPtr, 0, 0));
+        assertEquals(-1, CharsetUtils.toUtf8Bytes("foo", destPtr, 0, 2));
+        assertEquals(-1, CharsetUtils.toUtf8Bytes("foo", destPtr, -2, 8));
+        assertEquals(-1, CharsetUtils.toUtf8Bytes("foo", destPtr, 6, 8));
+        assertEquals(-1, CharsetUtils.toUtf8Bytes("foo", destPtr, 10, 8));
+    }
+
+    @Test
+    public void testUtf8_Overwrite() {
+        assertEquals(5, CharsetUtils.toUtf8Bytes("!!!!!", destPtr, 0, dest.length));
+        assertEquals(3, CharsetUtils.toUtf8Bytes("...", destPtr, 0, dest.length));
+        assertEquals(1, CharsetUtils.toUtf8Bytes("?", destPtr, 0, dest.length));
+        assertEquals("3F002E0021000000", HexDump.toHexString(dest));
+    }
+}
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
new file mode 100644
index 0000000..2ae9cdf
--- /dev/null
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import android.os.PersistableBundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.XmlUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class XmlTest {
+    @Test
+    public void testLargeValues_Normal() throws Exception {
+        doLargeValues(XmlUtils.makeTyped(Xml.newSerializer()),
+                XmlUtils.makeTyped(Xml.newPullParser()));
+    }
+
+    @Test
+    public void testLargeValues_Fast() throws Exception {
+        doLargeValues(Xml.newFastSerializer(),
+                Xml.newFastPullParser());
+    }
+
+    @Test
+    public void testLargeValues_Binary() throws Exception {
+        doLargeValues(Xml.newBinarySerializer(),
+                Xml.newBinaryPullParser());
+    }
+
+    /**
+     * Verify that we can write and read large {@link String} and {@code byte[]}
+     * without issues.
+     */
+    private static void doLargeValues(TypedXmlSerializer out, TypedXmlPullParser in)
+            throws Exception {
+        final char[] chars = new char[(1 << 16) - 1];
+        Arrays.fill(chars, '!');
+
+        final String string = new String(chars);
+        final byte[] bytes = string.getBytes();
+        assertEquals(chars.length, bytes.length);
+
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        out.setOutput(os, StandardCharsets.UTF_8.name());
+        out.startTag(null, "tag");
+        out.attribute(null, "string", string);
+        out.attributeBytesBase64(null, "bytes", bytes);
+        out.endTag(null, "tag");
+        out.flush();
+
+        final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+        in.setInput(is, StandardCharsets.UTF_8.name());
+        assertNext(in, START_TAG, "tag", 1);
+        assertEquals(2, in.getAttributeCount());
+        assertEquals(string, in.getAttributeValue(null, "string"));
+        assertArrayEquals(bytes, in.getAttributeBytesBase64(null, "bytes"));
+    }
+
+    @Test
+    public void testPersistableBundle_Normal() throws Exception {
+        doPersistableBundle(XmlUtils.makeTyped(Xml.newSerializer()),
+                XmlUtils.makeTyped(Xml.newPullParser()));
+    }
+
+    @Test
+    public void testPersistableBundle_Fast() throws Exception {
+        doPersistableBundle(Xml.newFastSerializer(),
+                Xml.newFastPullParser());
+    }
+
+    @Test
+    public void testPersistableBundle_Binary() throws Exception {
+        doPersistableBundle(Xml.newBinarySerializer(),
+                Xml.newBinaryPullParser());
+    }
+
+    /**
+     * Verify that a complex {@link PersistableBundle} can be serialized out and
+     * then parsed in with the original structure intact.
+     */
+    private static void doPersistableBundle(TypedXmlSerializer out, TypedXmlPullParser in)
+            throws Exception {
+        final PersistableBundle expected = buildPersistableBundle();
+        final byte[] raw = doPersistableBundleWrite(out, expected);
+
+        // Yes, this string-based check is fragile, but kindofEquals() is broken
+        // when working with nested objects and arrays
+        final PersistableBundle actual = doPersistableBundleRead(in, raw);
+        assertEquals(expected.toString(), actual.toString());
+    }
+
+    static PersistableBundle buildPersistableBundle() {
+        final PersistableBundle outer = new PersistableBundle();
+
+        outer.putBoolean("boolean", true);
+        outer.putInt("int", 42);
+        outer.putLong("long", 43L);
+        outer.putDouble("double", 44d);
+        outer.putString("string", "com.example <and></and> &amp; more");
+
+        outer.putBooleanArray("boolean[]", new boolean[] { true, false, true });
+        outer.putIntArray("int[]", new int[] { 42, 43, 44 });
+        outer.putLongArray("long[]", new long[] { 43L, 44L, 45L });
+        outer.putDoubleArray("double[]", new double[] { 43d, 44d, 45d });
+        outer.putStringArray("string[]", new String[] { "foo", "bar", "baz" });
+
+        final PersistableBundle nested = new PersistableBundle();
+        nested.putString("nested_key", "nested_value");
+        outer.putPersistableBundle("nested", nested);
+
+        return outer;
+    }
+
+    static byte[] doPersistableBundleWrite(TypedXmlSerializer out, PersistableBundle bundle)
+            throws Exception {
+        // We purposefully omit START/END_DOCUMENT events here to verify correct
+        // behavior of what PersistableBundle does internally
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        out.setOutput(os, StandardCharsets.UTF_8.name());
+        out.startTag(null, "bundle");
+        bundle.saveToXml(out);
+        out.endTag(null, "bundle");
+        out.flush();
+        return os.toByteArray();
+    }
+
+    static PersistableBundle doPersistableBundleRead(TypedXmlPullParser in, byte[] raw)
+            throws Exception {
+        final ByteArrayInputStream is = new ByteArrayInputStream(raw);
+        in.setInput(is, StandardCharsets.UTF_8.name());
+        in.next();
+        return PersistableBundle.restoreFromXml(in);
+    }
+
+    @Test
+    public void testVerify_Normal() throws Exception {
+        doVerify(XmlUtils.makeTyped(Xml.newSerializer()),
+                XmlUtils.makeTyped(Xml.newPullParser()));
+    }
+
+    @Test
+    public void testVerify_Fast() throws Exception {
+        doVerify(Xml.newFastSerializer(),
+                Xml.newFastPullParser());
+    }
+
+    @Test
+    public void testVerify_Binary() throws Exception {
+        doVerify(Xml.newBinarySerializer(),
+                Xml.newBinaryPullParser());
+    }
+
+    /**
+     * Verify that example test data is correctly serialized and parsed
+     * end-to-end using the given objects.
+     */
+    private static void doVerify(TypedXmlSerializer out, TypedXmlPullParser in) throws Exception {
+        final ByteArrayOutputStream os = new ByteArrayOutputStream();
+        out.setOutput(os, StandardCharsets.UTF_8.name());
+        doVerifyWrite(out);
+        out.flush();
+
+        final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+        in.setInput(is, StandardCharsets.UTF_8.name());
+        doVerifyRead(in);
+    }
+
+    private static final String TEST_STRING = "com.example";
+    private static final byte[] TEST_BYTES = new byte[] { 0, 1, 2, 3, 4, 3, 2, 1, 0 };
+
+    private static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
+        out.startDocument(StandardCharsets.UTF_8.name(), true);
+        out.startTag(null, "one");
+        {
+            out.startTag(null, "two");
+            {
+                out.attribute(null, "string", TEST_STRING);
+                out.attribute(null, "stringNumber", "49");
+                out.attributeBytesHex(null, "bytesHex", TEST_BYTES);
+                out.attributeBytesBase64(null, "bytesBase64", TEST_BYTES);
+                out.attributeInt(null, "int", 43);
+                out.attributeIntHex(null, "intHex", 44);
+                out.attributeLong(null, "long", 45L);
+                out.attributeLongHex(null, "longHex", 46L);
+                out.attributeFloat(null, "float", 47f);
+                out.attributeDouble(null, "double", 48d);
+                out.attributeBoolean(null, "boolean", true);
+            }
+            out.endTag(null, "two");
+
+            out.startTag(null, "three");
+            {
+                out.text("foo");
+                out.startTag(null, "four");
+                {
+                }
+                out.endTag(null, "four");
+                out.text("bar");
+                out.text("baz");
+            }
+            out.endTag(null, "three");
+        }
+        out.endTag(null, "one");
+        out.endDocument();
+    }
+
+    private static void doVerifyRead(TypedXmlPullParser in) throws Exception {
+        assertEquals(START_DOCUMENT, in.getEventType());
+        assertNext(in, START_TAG, "one", 1);
+        {
+            assertNext(in, START_TAG, "two", 2);
+            {
+                assertEquals(11, in.getAttributeCount());
+                assertEquals(TEST_STRING, in.getAttributeValue(null, "string"));
+                assertArrayEquals(TEST_BYTES, in.getAttributeBytesHex(null, "bytesHex"));
+                assertArrayEquals(TEST_BYTES, in.getAttributeBytesBase64(null, "bytesBase64"));
+                assertEquals(43, in.getAttributeInt(null, "int"));
+                assertEquals(44, in.getAttributeIntHex(null, "intHex"));
+                assertEquals(45L, in.getAttributeLong(null, "long"));
+                assertEquals(46L, in.getAttributeLongHex(null, "longHex"));
+                assertEquals(47f, in.getAttributeFloat(null, "float"), 0.01);
+                assertEquals(48d, in.getAttributeDouble(null, "double"), 0.01);
+                assertEquals(true, in.getAttributeBoolean(null, "boolean"));
+
+                // Also verify that typed values are available as strings
+                assertEquals("000102030403020100", in.getAttributeValue(null, "bytesHex"));
+                assertEquals("AAECAwQDAgEA", in.getAttributeValue(null, "bytesBase64"));
+                assertEquals("43", in.getAttributeValue(null, "int"));
+                assertEquals("2c", in.getAttributeValue(null, "intHex"));
+                assertEquals("45", in.getAttributeValue(null, "long"));
+                assertEquals("2e", in.getAttributeValue(null, "longHex"));
+                assertEquals("true", in.getAttributeValue(null, "boolean"));
+
+                // And that raw strings can be parsed too
+                assertEquals("49", in.getAttributeValue(null, "stringNumber"));
+                assertEquals(49, in.getAttributeInt(null, "stringNumber"));
+            }
+            assertNext(in, END_TAG, "two", 2);
+
+            assertNext(in, START_TAG, "three", 2);
+            {
+                assertNext(in, TEXT);
+                assertEquals("foo", in.getText().trim());
+                assertNext(in, START_TAG, "four", 3);
+                {
+                    assertEquals(0, in.getAttributeCount());
+                }
+                assertNext(in, END_TAG, "four", 3);
+                assertNext(in, TEXT);
+                assertEquals("barbaz", in.getText().trim());
+            }
+            assertNext(in, END_TAG, "three", 2);
+        }
+        assertNext(in, END_TAG, "one", 1);
+        assertNext(in, END_DOCUMENT);
+    }
+
+    static void assertNext(TypedXmlPullParser in, int token) throws Exception {
+        // We're willing to skip over empty text regions, which some
+        // serializers emit transparently
+        int event;
+        while ((event = in.next()) == TEXT && in.getText().trim().length() == 0) {
+        }
+        assertEquals("next", token, event);
+        assertEquals("getEventType", token, in.getEventType());
+    }
+
+    static void assertNext(TypedXmlPullParser in, int token, String name, int depth)
+            throws Exception {
+        assertNext(in, token);
+        assertEquals("getName", name, in.getName());
+        assertEquals("getDepth", depth, in.getDepth());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
new file mode 100644
index 0000000..841d659
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
@@ -0,0 +1,348 @@
+/*
+ * 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.internal.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.util.ExceptionUtils;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+public class FastDataTest {
+    private static final String TEST_SHORT_STRING = "a";
+    private static final String TEST_LONG_STRING = "com☃example☃typical☃package☃name";
+    private static final byte[] TEST_BYTES = TEST_LONG_STRING.getBytes(StandardCharsets.UTF_16LE);
+
+    @Test
+    public void testEndOfFile_Int() throws Exception {
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1 }), 1000)) {
+            assertThrows(EOFException.class, () -> in.readInt());
+        }
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1, 1, 1, 1 }), 1000)) {
+            assertEquals(1, in.readByte());
+            assertThrows(EOFException.class, () -> in.readInt());
+        }
+    }
+
+    @Test
+    public void testEndOfFile_String() throws Exception {
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1 }), 1000)) {
+            assertThrows(EOFException.class, () -> in.readUTF());
+        }
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1, 1, 1, 1 }), 1000)) {
+            assertThrows(EOFException.class, () -> in.readUTF());
+        }
+    }
+
+    @Test
+    public void testEndOfFile_Bytes_Small() throws Exception {
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1, 1, 1, 1 }), 1000)) {
+            final byte[] tmp = new byte[10];
+            assertThrows(EOFException.class, () -> in.readFully(tmp));
+        }
+        try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+                new byte[] { 1, 1, 1, 1 }), 1000)) {
+            final byte[] tmp = new byte[10_000];
+            assertThrows(EOFException.class, () -> in.readFully(tmp));
+        }
+    }
+
+    @Test
+    public void testUTF_Bounds() throws Exception {
+        final char[] buf = new char[65_535];
+        try (FastDataOutput out = new FastDataOutput(new ByteArrayOutputStream(), BOUNCE_SIZE)) {
+            // Writing simple string will fit fine
+            Arrays.fill(buf, '!');
+            final String simple = new String(buf);
+            out.writeUTF(simple);
+            out.writeInternedUTF(simple);
+
+            // Just one complex char will cause it to overflow
+            buf[0] = '☃';
+            final String complex = new String(buf);
+            assertThrows(IOException.class, () -> out.writeUTF(complex));
+            assertThrows(IOException.class, () -> out.writeInternedUTF(complex));
+        }
+    }
+
+    @Test
+    public void testBounce_Char() throws Exception {
+        doBounce((out) -> {
+            out.writeChar('\0');
+            out.writeChar('☃');
+        }, (in) -> {
+            assertEquals('\0', in.readChar());
+            assertEquals('☃', in.readChar());
+        });
+    }
+
+    @Test
+    public void testBounce_Short() throws Exception {
+        doBounce((out) -> {
+            out.writeShort(0);
+            out.writeShort((short) 0x0f0f);
+            out.writeShort((short) 0xf0f0);
+            out.writeShort(Short.MIN_VALUE);
+            out.writeShort(Short.MAX_VALUE);
+        }, (in) -> {
+            assertEquals(0, in.readShort());
+            assertEquals((short) 0x0f0f, in.readShort());
+            assertEquals((short) 0xf0f0, in.readShort());
+            assertEquals(Short.MIN_VALUE, in.readShort());
+            assertEquals(Short.MAX_VALUE, in.readShort());
+        });
+    }
+
+    @Test
+    public void testBounce_Int() throws Exception {
+        doBounce((out) -> {
+            out.writeInt(0);
+            out.writeInt(0x0f0f0f0f);
+            out.writeInt(0xf0f0f0f0);
+            out.writeInt(Integer.MIN_VALUE);
+            out.writeInt(Integer.MAX_VALUE);
+        }, (in) -> {
+            assertEquals(0, in.readInt());
+            assertEquals(0x0f0f0f0f, in.readInt());
+            assertEquals(0xf0f0f0f0, in.readInt());
+            assertEquals(Integer.MIN_VALUE, in.readInt());
+            assertEquals(Integer.MAX_VALUE, in.readInt());
+        });
+    }
+
+    @Test
+    public void testBounce_Long() throws Exception {
+        doBounce((out) -> {
+            out.writeLong(0);
+            out.writeLong(0x0f0f0f0f0f0f0f0fL);
+            out.writeLong(0xf0f0f0f0f0f0f0f0L);
+            out.writeLong(Long.MIN_VALUE);
+            out.writeLong(Long.MAX_VALUE);
+        }, (in) -> {
+            assertEquals(0, in.readLong());
+            assertEquals(0x0f0f0f0f0f0f0f0fL, in.readLong());
+            assertEquals(0xf0f0f0f0f0f0f0f0L, in.readLong());
+            assertEquals(Long.MIN_VALUE, in.readLong());
+            assertEquals(Long.MAX_VALUE, in.readLong());
+        });
+    }
+
+    @Test
+    public void testBounce_UTF() throws Exception {
+        doBounce((out) -> {
+            out.writeUTF("");
+            out.writeUTF("☃");
+            out.writeUTF("example");
+        }, (in) -> {
+            assertEquals("", in.readUTF());
+            assertEquals("☃", in.readUTF());
+            assertEquals("example", in.readUTF());
+        });
+    }
+
+    @Test
+    public void testBounce_UTF_Exact() throws Exception {
+        final char[] expectedBuf = new char[BOUNCE_SIZE];
+        Arrays.fill(expectedBuf, '!');
+        final String expected = new String(expectedBuf);
+
+        doBounce((out) -> {
+            out.writeUTF(expected);
+        }, (in) -> {
+            final String actual = in.readUTF();
+            assertEquals(expected.length(), actual.length());
+            assertEquals(expected, actual);
+        });
+    }
+
+    @Test
+    public void testBounce_UTF_Maximum() throws Exception {
+        final char[] expectedBuf = new char[65_535];
+        Arrays.fill(expectedBuf, '!');
+        final String expected = new String(expectedBuf);
+
+        doBounce((out) -> {
+            out.writeUTF(expected);
+        }, (in) -> {
+            final String actual = in.readUTF();
+            assertEquals(expected.length(), actual.length());
+            assertEquals(expected, actual);
+        }, 1);
+    }
+
+    @Test
+    public void testBounce_InternedUTF() throws Exception {
+        doBounce((out) -> {
+            out.writeInternedUTF("foo");
+            out.writeInternedUTF("bar");
+            out.writeInternedUTF("baz");
+            out.writeInternedUTF("bar");
+            out.writeInternedUTF("foo");
+        }, (in) -> {
+            assertEquals("foo", in.readInternedUTF());
+            assertEquals("bar", in.readInternedUTF());
+            assertEquals("baz", in.readInternedUTF());
+            assertEquals("bar", in.readInternedUTF());
+            assertEquals("foo", in.readInternedUTF());
+        });
+    }
+
+    /**
+     * Verify that when we overflow the maximum number of interned string
+     * references, we still transport the raw string values successfully.
+     */
+    @Test
+    public void testBounce_InternedUTF_Maximum() throws Exception {
+        final int num = 70_000;
+        doBounce((out) -> {
+            for (int i = 0; i < num; i++) {
+                out.writeInternedUTF("foo" + i);
+            }
+        }, (in) -> {
+            for (int i = 0; i < num; i++) {
+                assertEquals("foo" + i, in.readInternedUTF());
+            }
+        }, 1);
+    }
+
+    @Test
+    public void testBounce_Bytes() throws Exception {
+        doBounce((out) -> {
+            out.write(TEST_BYTES, 8, 32);
+            out.writeInt(64);
+        }, (in) -> {
+            final byte[] tmp = new byte[128];
+            in.readFully(tmp, 8, 32);
+            assertArrayEquals(Arrays.copyOfRange(TEST_BYTES, 8, 8 + 32),
+                    Arrays.copyOfRange(tmp, 8, 8 + 32));
+            assertEquals(64, in.readInt());
+        });
+    }
+
+    @Test
+    public void testBounce_Mixed() throws Exception {
+        doBounce((out) -> {
+            out.writeBoolean(true);
+            out.writeBoolean(false);
+            out.writeByte(1);
+            out.writeShort(2);
+            out.writeInt(4);
+            out.writeUTF(TEST_SHORT_STRING);
+            out.writeUTF(TEST_LONG_STRING);
+            out.writeLong(8L);
+            out.writeFloat(16f);
+            out.writeDouble(32d);
+        }, (in) -> {
+            assertEquals(true, in.readBoolean());
+            assertEquals(false, in.readBoolean());
+            assertEquals(1, in.readByte());
+            assertEquals(2, in.readShort());
+            assertEquals(4, in.readInt());
+            assertEquals(TEST_SHORT_STRING, in.readUTF());
+            assertEquals(TEST_LONG_STRING, in.readUTF());
+            assertEquals(8L, in.readLong());
+            assertEquals(16f, in.readFloat(), 0.01);
+            assertEquals(32d, in.readDouble(), 0.01);
+        });
+    }
+
+    /**
+     * Buffer size to use for {@link #doBounce}; purposefully chosen to be a
+     * small prime number to help uncover edge cases.
+     */
+    private static final int BOUNCE_SIZE = 11;
+
+    /**
+     * Number of times to repeat message when bouncing; repeating is used to
+     * help uncover edge cases.
+     */
+    private static final int BOUNCE_REPEAT = 1_000;
+
+    /**
+     * Verify that some common data can be written and read back, effectively
+     * "bouncing" it through a serialized representation.
+     */
+    private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out,
+            @NonNull ThrowingConsumer<FastDataInput> in) throws Exception {
+        doBounce(out, in, BOUNCE_REPEAT);
+    }
+
+    private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out,
+            @NonNull ThrowingConsumer<FastDataInput> in, int count) throws Exception {
+        final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+        final FastDataOutput outData = new FastDataOutput(outStream, BOUNCE_SIZE);
+        for (int i = 0; i < count; i++) {
+            out.accept(outData);
+        }
+        outData.flush();
+
+        final ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
+        final FastDataInput inData = new FastDataInput(inStream, BOUNCE_SIZE);
+        for (int i = 0; i < count; i++) {
+            in.accept(inData);
+        }
+    }
+
+    private static <T extends Exception> void assertThrows(Class<T> clazz, ThrowingRunnable r)
+            throws Exception {
+        try {
+            r.run();
+            fail("Expected " + clazz + " to be thrown");
+        } catch (Exception e) {
+            if (!clazz.isAssignableFrom(e.getClass())) {
+                throw e;
+            }
+        }
+    }
+
+    public interface ThrowingRunnable {
+        void run() throws Exception;
+    }
+
+    public interface ThrowingConsumer<T> extends Consumer<T> {
+        void acceptOrThrow(T t) throws Exception;
+
+        @Override
+        default void accept(T t) {
+            try {
+                acceptOrThrow(t);
+            } catch (Exception ex) {
+                throw ExceptionUtils.propagate(ex);
+            }
+        }
+    }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index d266cdb..46695d2 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -26,15 +26,16 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -52,7 +53,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
-import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
@@ -200,9 +201,9 @@
     private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) {
         clearInvocations(activityThread);
         getInstrumentation().runOnMainSync(() -> activity.recreate());
+        getInstrumentation().waitForIdleSync();
 
-        verify(activityThread, after(WAIT_TIMEOUT_MS).never())
-                .handleRelaunchActivity(any(), any());
+        verify(activityThread, never()).handleRelaunchActivity(any(), any());
     }
 
     private void recreateAndVerifyRelaunched(ActivityThread activityThread, TestActivity activity,
@@ -292,7 +293,7 @@
             spyOn(packageInfo);
             doNothing().when(packageInfo).updateApplicationInfo(any(), any());
 
-            return new ActivityClientRecord(new Binder(), Intent.makeMainActivity(component),
+            return new ActivityClientRecord(mock(IBinder.class), Intent.makeMainActivity(component),
                     0 /* ident */, info, new Configuration(),
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
                     null /* voiceInteractor */, null /* state */, null /* persistentState */,
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 94bfdc9..4309ab2 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.Nullable;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -60,8 +61,13 @@
         return nativeGetSurface(mNativeObject, true /* includeSurfaceControlHandle */);
     }
 
-    public void setNextTransaction(SurfaceControl.Transaction t) {
-        nativeSetNextTransaction(mNativeObject, t.mNativeObject);
+    /**
+     * Send the transaction to BBQ so the next frame can be added and not applied immediately.
+     * This gives the caller a chance to apply the transaction when it's ready.
+     * @param t The transaction to add the frame to. This can be null to clear the transaction.
+     */
+    public void setNextTransaction(@Nullable SurfaceControl.Transaction t) {
+        nativeSetNextTransaction(mNativeObject, t == null ? 0 : t.mNativeObject);
     }
 
     public void update(SurfaceControl sc, int width, int height) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 441c163..c58e5f3 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -56,6 +56,7 @@
 import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -1209,6 +1210,36 @@
         return Arrays.binarySearch(mSupportedAxes, axis) >= 0;
     }
 
+    /**
+     * Writes Typeface instances to the ByteBuffer and returns the number of bytes written.
+     *
+     * <p>If {@code buffer} is null, this method returns the number of bytes required to serialize
+     * the typefaces, without writing anything.
+     * @hide
+     */
+    public static int writeTypefaces(
+            @Nullable ByteBuffer buffer, @NonNull List<Typeface> typefaces) {
+        long[] nativePtrs = new long[typefaces.size()];
+        for (int i = 0; i < nativePtrs.length; i++) {
+            nativePtrs[i] = typefaces.get(i).native_instance;
+        }
+        return nativeWriteTypefaces(buffer, nativePtrs);
+    }
+
+    /**
+     * Reads serialized Typeface instances from the ByteBuffer. Returns null on errors.
+     * @hide
+     */
+    public static @Nullable List<Typeface> readTypefaces(@NonNull ByteBuffer buffer) {
+        long[] nativePtrs = nativeReadTypefaces(buffer);
+        if (nativePtrs == null) return null;
+        List<Typeface> typefaces = new ArrayList<>(nativePtrs.length);
+        for (long nativePtr : nativePtrs) {
+            typefaces.add(new Typeface(nativePtr));
+        }
+        return typefaces;
+    }
+
     private static native long nativeCreateFromTypeface(long native_instance, int style);
     private static native long nativeCreateFromTypefaceWithExactStyle(
             long native_instance, int weight, boolean italic);
@@ -1234,4 +1265,9 @@
     private static native long nativeGetReleaseFunc();
 
     private static native void nativeRegisterGenericFamily(String str, long nativePtr);
+
+    private static native int nativeWriteTypefaces(
+            @Nullable ByteBuffer buffer, @NonNull long[] nativePtrs);
+
+    private static native @Nullable long[] nativeReadTypefaces(@NonNull ByteBuffer buffer);
 }
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index d8474b8..0d684e8 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -15,6 +15,7 @@
     limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/tv_pip_menu"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:orientation="horizontal"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 51ddb17..2d20fee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -346,15 +346,9 @@
         return mTaskListeners.get(taskListenerType);
     }
 
-    @WindowingMode
-    public static int getWindowingMode(RunningTaskInfo taskInfo) {
-        return taskInfo.configuration.windowConfiguration.getWindowingMode();
-    }
-
     @VisibleForTesting
     static @TaskListenerType int taskInfoToTaskListenerType(RunningTaskInfo runningTaskInfo) {
-        final int windowingMode = getWindowingMode(runningTaskInfo);
-        switch (windowingMode) {
+        switch (runningTaskInfo.getWindowingMode()) {
             case WINDOWING_MODE_FULLSCREEN:
                 return runningTaskInfo.letterboxActivityBounds != null
                         ? TASK_LISTENER_TYPE_LETTERBOX
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
new file mode 100644
index 0000000..87ddb18
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the input consumer that allows the Shell to directly receive input.
+ */
+public class PipInputConsumer {
+
+    private static final String TAG = PipInputConsumer.class.getSimpleName();
+
+    /**
+     * Listener interface for callers to subscribe to input events.
+     */
+    public interface InputListener {
+        /** Handles any input event. */
+        boolean onInputEvent(InputEvent ev);
+    }
+
+    /**
+     * Listener interface for callers to learn when this class is registered or unregistered with
+     * window manager
+     */
+    public interface RegistrationListener {
+        void onRegistrationChanged(boolean isRegistered);
+    }
+
+    /**
+     * Input handler used for the input consumer. Input events are batched and consumed with the
+     * SurfaceFlinger vsync.
+     */
+    private final class InputEventReceiver extends BatchedInputEventReceiver {
+
+        InputEventReceiver(InputChannel inputChannel, Looper looper,
+                Choreographer choreographer) {
+            super(inputChannel, looper, choreographer);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            boolean handled = true;
+            try {
+                if (mListener != null) {
+                    handled = mListener.onInputEvent(event);
+                }
+            } finally {
+                finishInputEvent(event, handled);
+            }
+        }
+    }
+
+    private final IWindowManager mWindowManager;
+    private final IBinder mToken;
+    private final String mName;
+
+    private InputEventReceiver mInputEventReceiver;
+    private InputListener mListener;
+    private RegistrationListener mRegistrationListener;
+
+    /**
+     * @param name the name corresponding to the input consumer that is defined in the system.
+     */
+    public PipInputConsumer(IWindowManager windowManager, String name) {
+        mWindowManager = windowManager;
+        mToken = new Binder();
+        mName = name;
+    }
+
+    /**
+     * Sets the input listener.
+     */
+    public void setInputListener(InputListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets the registration listener.
+     */
+    public void setRegistrationListener(RegistrationListener listener) {
+        mRegistrationListener = listener;
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null);
+        }
+    }
+
+    /**
+     * Check if the InputConsumer is currently registered with WindowManager
+     *
+     * @return {@code true} if registered, {@code false} if not.
+     */
+    public boolean isRegistered() {
+        return mInputEventReceiver != null;
+    }
+
+    /**
+     * Registers the input consumer.
+     */
+    public void registerInputConsumer() {
+        registerInputConsumer(false);
+    }
+
+    /**
+     * Registers the input consumer.
+     * @param withSfVsync the flag set using sf vsync signal or no
+     */
+    public void registerInputConsumer(boolean withSfVsync) {
+        if (mInputEventReceiver != null) {
+            return;
+        }
+        final InputChannel inputChannel = new InputChannel();
+        try {
+            // TODO(b/113087003): Support Picture-in-picture in multi-display.
+            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+            mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to create input consumer", e);
+        }
+        mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
+                withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
+        }
+    }
+
+    /**
+     * Unregisters the input consumer.
+     */
+    public void unregisterInputConsumer() {
+        if (mInputEventReceiver == null) {
+            return;
+        }
+        try {
+            // TODO(b/113087003): Support Picture-in-picture in multi-display.
+            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to destroy input consumer", e);
+        }
+        mInputEventReceiver.dispose();
+        mInputEventReceiver = null;
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(false /* isRegistered */);
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + TAG);
+        pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
new file mode 100644
index 0000000..0f6dd93
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -0,0 +1,116 @@
+/*
+ * 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.wm.shell.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskStackListener;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.os.IBinder;
+
+import androidx.annotation.BinderThread;
+import androidx.annotation.MainThread;
+
+/**
+ * An interface to track task stack changes. Classes should implement this instead of
+ * {@link ITaskStackListener} to reduce IPC calls from system services.
+ */
+public interface TaskStackListenerCallback {
+
+    @MainThread
+    default void onRecentTaskListUpdated() { }
+
+    @MainThread
+    default void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+    @BinderThread
+    default void onTaskStackChangedBackground() { }
+
+    @MainThread
+    default void onTaskStackChanged() { }
+
+    @MainThread
+    default void onTaskProfileLocked(int taskId, int userId) { }
+
+    @MainThread
+    default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
+
+    @MainThread
+    default void onTaskCreated(int taskId, ComponentName componentName) { }
+
+    @MainThread
+    default void onTaskRemoved(int taskId) { }
+
+    @MainThread
+    default void onTaskMovedToFront(int taskId) { }
+
+    @MainThread
+    default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+        onTaskMovedToFront(taskInfo.taskId);
+    }
+
+    @MainThread
+    default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
+
+    @MainThread
+    default void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) { }
+
+    @MainThread
+    default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
+
+    @MainThread
+    default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask, boolean wasVisible) { }
+
+    @MainThread
+    default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
+
+    @MainThread
+    default void onActivityUnpinned() { }
+
+    @MainThread
+    default void onActivityForcedResizable(String packageName, int taskId, int reason) { }
+
+    @MainThread
+    default void onActivityDismissingDockedStack() { }
+
+    @MainThread
+    default void onActivityLaunchOnSecondaryDisplayFailed() { }
+
+    @MainThread
+    default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+        onActivityLaunchOnSecondaryDisplayFailed();
+    }
+
+    @MainThread
+    default void onActivityLaunchOnSecondaryDisplayRerouted() { }
+
+    @MainThread
+    default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
+        onActivityLaunchOnSecondaryDisplayRerouted();
+    }
+
+    @MainThread
+    default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
+
+    @MainThread
+    default void onActivityRotation(int displayId) { }
+
+    @MainThread
+    default void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
new file mode 100644
index 0000000..7efacc7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -0,0 +1,437 @@
+/*
+ * 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.wm.shell.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Trace;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a {@link android.app.TaskStackListener}.
+ */
+public class TaskStackListenerImpl extends TaskStackListener implements Handler.Callback {
+    private static final String TAG = TaskStackListenerImpl.class.getSimpleName();
+
+    private static final int ON_TASK_STACK_CHANGED = 1;
+    private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+    private static final int ON_ACTIVITY_PINNED = 3;
+    private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
+    private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
+    private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
+    private static final int ON_TASK_PROFILE_LOCKED = 7;
+    private static final int ON_ACTIVITY_UNPINNED = 8;
+    private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 9;
+    private static final int ON_TASK_CREATED = 10;
+    private static final int ON_TASK_REMOVED = 11;
+    private static final int ON_TASK_MOVED_TO_FRONT = 12;
+    private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 13;
+    private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 14;
+    private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 15;
+    private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 16;
+    private static final int ON_TASK_DISPLAY_CHANGED = 17;
+    private static final int ON_TASK_LIST_UPDATED = 18;
+    private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 19;
+    private static final int ON_TASK_DESCRIPTION_CHANGED = 20;
+    private static final int ON_ACTIVITY_ROTATION = 21;
+
+    /**
+     * List of {@link TaskStackListenerCallback} registered from {@link #addListener}.
+     */
+    private final List<TaskStackListenerCallback> mTaskStackListeners = new ArrayList<>();
+    private final List<TaskStackListenerCallback> mTmpListeners = new ArrayList<>();
+
+    private final IActivityTaskManager mActivityTaskManager;
+    // NOTE: In this case we do want to use a handler since we rely on the message system to
+    // efficiently dedupe sequential calls
+    private Handler mHandler;
+
+    public TaskStackListenerImpl(Handler handler) {
+        mActivityTaskManager = ActivityTaskManager.getService();
+        mHandler = new Handler(handler.getLooper(), this);
+    }
+
+    @VisibleForTesting
+    TaskStackListenerImpl(IActivityTaskManager activityTaskManager) {
+        mActivityTaskManager = activityTaskManager;
+    }
+
+    @VisibleForTesting
+    void setHandler(Handler handler) {
+        mHandler = handler;
+    }
+
+    public void addListener(TaskStackListenerCallback listener) {
+        final boolean wasEmpty;
+        synchronized (mTaskStackListeners) {
+            wasEmpty = mTaskStackListeners.isEmpty();
+            mTaskStackListeners.add(listener);
+        }
+        if (wasEmpty) {
+            // Register mTaskStackListener to IActivityManager only once if needed.
+            try {
+                mActivityTaskManager.registerTaskStackListener(this);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to call registerTaskStackListener", e);
+            }
+        }
+    }
+
+    public void removeListener(TaskStackListenerCallback listener) {
+        final boolean wasEmpty;
+        final boolean isEmpty;
+        synchronized (mTaskStackListeners) {
+            wasEmpty = mTaskStackListeners.isEmpty();
+            mTaskStackListeners.remove(listener);
+            isEmpty = mTaskStackListeners.isEmpty();
+        }
+        if (!wasEmpty && isEmpty) {
+            // Unregister mTaskStackListener once we have no more listeners
+            try {
+                mActivityTaskManager.unregisterTaskStackListener(this);
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
+            }
+        }
+    }
+
+    @Override
+    public void onRecentTaskListUpdated() {
+        mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
+    }
+
+    @Override
+    public void onRecentTaskListFrozenChanged(boolean frozen) {
+        mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
+                .sendToTarget();
+    }
+
+    @Override
+    public void onTaskStackChanged() {
+        // Call the task changed callback for the non-ui thread listeners first. Copy to a set
+        // of temp listeners so that we don't lock on mTaskStackListeners while calling all the
+        // callbacks. This call is always on the same binder thread, so we can just synchronize
+        // on the copying of the listener list.
+        synchronized (mTaskStackListeners) {
+            mTmpListeners.addAll(mTaskStackListeners);
+        }
+        for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+            mTmpListeners.get(i).onTaskStackChangedBackground();
+        }
+        mTmpListeners.clear();
+
+        mHandler.removeMessages(ON_TASK_STACK_CHANGED);
+        mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
+    }
+
+    @Override
+    public void onTaskProfileLocked(int taskId, int userId) {
+        mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+    }
+
+    @Override
+    public void onTaskDisplayChanged(int taskId, int newDisplayId) {
+        mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
+    }
+
+    @Override
+    public void onTaskCreated(int taskId, ComponentName componentName) {
+        mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
+    }
+
+    @Override
+    public void onTaskRemoved(int taskId) {
+        mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
+    }
+
+    @Override
+    public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+        mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
+    }
+
+    @Override
+    public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
+    }
+
+    @Override
+    public void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) {
+        mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+    }
+
+    @Override
+    public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+        mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
+    }
+
+    @Override
+    public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = packageName;
+        args.argi1 = userId;
+        args.argi2 = taskId;
+        args.argi3 = stackId;
+        mHandler.removeMessages(ON_ACTIVITY_PINNED);
+        mHandler.obtainMessage(ON_ACTIVITY_PINNED, args).sendToTarget();
+    }
+
+    @Override
+    public void onActivityUnpinned() {
+        mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
+        mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
+    }
+
+    @Override
+    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask, boolean wasVisible) {
+        final SomeArgs args = SomeArgs.obtain();
+        args.arg1 = task;
+        args.argi1 = homeTaskVisible ? 1 : 0;
+        args.argi2 = clearedTask ? 1 : 0;
+        args.argi3 = wasVisible ? 1 : 0;
+        mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
+        mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
+    }
+
+    @Override
+    public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+        mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
+                .sendToTarget();
+    }
+
+    @Override
+    public void onActivityDismissingDockedStack() {
+        mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
+    }
+
+    @Override
+    public void onActivityLaunchOnSecondaryDisplayFailed(
+            ActivityManager.RunningTaskInfo taskInfo,
+            int requestedDisplayId) {
+        mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
+                requestedDisplayId,
+                0 /* unused */,
+                taskInfo).sendToTarget();
+    }
+
+    @Override
+    public void onActivityLaunchOnSecondaryDisplayRerouted(
+            ActivityManager.RunningTaskInfo taskInfo,
+            int requestedDisplayId) {
+        mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
+                requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
+    }
+
+    @Override
+    public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+        mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
+                requestedOrientation).sendToTarget();
+    }
+
+    @Override
+    public void onActivityRotation(int displayId) {
+        mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
+                .sendToTarget();
+    }
+
+    @Override
+    public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
+        mHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
+                0 /* unused */,
+                activityToken).sendToTarget();
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        synchronized (mTaskStackListeners) {
+            switch (msg.what) {
+                case ON_TASK_STACK_CHANGED: {
+                    Trace.beginSection("onTaskStackChanged");
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskStackChanged();
+                    }
+                    Trace.endSection();
+                    break;
+                }
+                case ON_TASK_SNAPSHOT_CHANGED: {
+                    Trace.beginSection("onTaskSnapshotChanged");
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+                                (ActivityManager.TaskSnapshot) msg.obj);
+                    }
+                    Trace.endSection();
+                    break;
+                }
+                case ON_ACTIVITY_PINNED: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityPinned((String) args.arg1, args.argi1,
+                                args.argi2, args.argi3);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_UNPINNED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityUnpinned();
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_RESTART_ATTEMPT: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    final ActivityManager.RunningTaskInfo
+                            task = (ActivityManager.RunningTaskInfo) args.arg1;
+                    final boolean homeTaskVisible = args.argi1 != 0;
+                    final boolean clearedTask = args.argi2 != 0;
+                    final boolean wasVisible = args.argi3 != 0;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+                                homeTaskVisible, clearedTask, wasVisible);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_FORCED_RESIZABLE: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityForcedResizable(
+                                (String) msg.obj, msg.arg1, msg.arg2);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+                    final ActivityManager.RunningTaskInfo
+                            info = (ActivityManager.RunningTaskInfo) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i)
+                                .onActivityLaunchOnSecondaryDisplayFailed(info);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED: {
+                    final ActivityManager.RunningTaskInfo
+                            info = (ActivityManager.RunningTaskInfo) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i)
+                                .onActivityLaunchOnSecondaryDisplayRerouted(info);
+                    }
+                    break;
+                }
+                case ON_TASK_PROFILE_LOCKED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+                    }
+                    break;
+                }
+                case ON_TASK_CREATED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskCreated(msg.arg1,
+                                (ComponentName) msg.obj);
+                    }
+                    break;
+                }
+                case ON_TASK_REMOVED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskRemoved(msg.arg1);
+                    }
+                    break;
+                }
+                case ON_TASK_MOVED_TO_FRONT: {
+                    final ActivityManager.RunningTaskInfo
+                            info = (ActivityManager.RunningTaskInfo) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskMovedToFront(info);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i)
+                                .onActivityRequestedOrientationChanged(msg.arg1, msg.arg2);
+                    }
+                    break;
+                }
+                case ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onSizeCompatModeActivityChanged(
+                                msg.arg1, (IBinder) msg.obj);
+                    }
+                    break;
+                }
+                case ON_BACK_PRESSED_ON_TASK_ROOT: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
+                                (ActivityManager.RunningTaskInfo) msg.obj);
+                    }
+                    break;
+                }
+                case ON_TASK_DISPLAY_CHANGED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
+                    }
+                    break;
+                }
+                case ON_TASK_LIST_UPDATED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onRecentTaskListUpdated();
+                    }
+                    break;
+                }
+                case ON_TASK_LIST_FROZEN_UNFROZEN: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(
+                                msg.arg1 != 0);
+                    }
+                    break;
+                }
+                case ON_TASK_DESCRIPTION_CHANGED: {
+                    final ActivityManager.RunningTaskInfo
+                            info = (ActivityManager.RunningTaskInfo) msg.obj;
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskDescriptionChanged(info);
+                    }
+                    break;
+                }
+                case ON_ACTIVITY_ROTATION: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onActivityRotation(msg.arg1);
+                    }
+                    break;
+                }
+            }
+        }
+        if (msg.obj instanceof SomeArgs) {
+            ((SomeArgs) msg.obj).recycle();
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 25890bc..8a547b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
@@ -67,6 +68,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * The policy for handling drag and drop operations to shell.
@@ -133,20 +135,20 @@
                 // TODO(b/169894807): For now, only allow splitting to the right/bottom until we
                 //                    have split pairs
                 mTargets.add(new Target(TYPE_FULLSCREEN,
-                        new Rect(0, 0, w, h / 2),
+                        new Rect(l, t, l + iw, t + ih / 2),
                         new Rect(l, t, l + iw, t + ih),
                         new Rect(0, 0, w, h)));
                 mTargets.add(new Target(TYPE_SPLIT_BOTTOM,
-                        new Rect(0, h / 2, w, h),
+                        new Rect(l, t + ih / 2, l + iw, t + ih),
                         new Rect(l, t + ih / 2, l + iw, t + ih),
                         new Rect(0, h / 2, w, h)));
             } else {
                 mTargets.add(new Target(TYPE_FULLSCREEN,
-                        new Rect(0, 0, w / 2, h),
+                        new Rect(l, t, l + iw / 2, t + ih),
                         new Rect(l, t, l + iw, t + ih),
                         new Rect(0, 0, w, h)));
                 mTargets.add(new Target(TYPE_SPLIT_RIGHT,
-                        new Rect(w / 2, 0, w, h),
+                        new Rect(l + iw / 2, t, l + iw, t + ih),
                         new Rect(l + iw / 2, t, l + iw, t + ih),
                         new Rect(w / 2, 0, w, h)));
             }
@@ -162,12 +164,12 @@
             secondarySplitBounds.intersect(new Rect(l, t, l + iw, t + ih));
             if (isVerticalSplit) {
                 mTargets.add(new Target(TYPE_FULLSCREEN,
-                        new Rect(0, 0, w, secondarySplitRawBounds.top),
+                        new Rect(l, t, l + iw, secondarySplitRawBounds.top),
                         new Rect(l, t, l + iw, t + ih),
                         new Rect(0, 0, w, secondarySplitRawBounds.top)));
             } else {
                 mTargets.add(new Target(TYPE_FULLSCREEN,
-                        new Rect(0, 0, secondarySplitRawBounds.left, h),
+                        new Rect(l, t, secondarySplitRawBounds.left, t + ih),
                         new Rect(l, t, l + iw, t + ih),
                         new Rect(0, 0, w, h)));
             }
@@ -178,7 +180,7 @@
         } else {
             // Otherwise only show the fullscreen target
             mTargets.add(new Target(TYPE_FULLSCREEN,
-                    new Rect(0, 0, w, h),
+                    new Rect(l, t, l + iw, t + ih),
                     new Rect(l, t, l + iw, t + ih),
                     new Rect(0, 0, w, h)));
         }
@@ -210,6 +212,7 @@
         final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
         final Intent dragData = mSession.dragData;
 
+        boolean deferAppLaunchUntilSplit = false;
         if (target.type == TYPE_FULLSCREEN) {
             if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
                 // If in split, remove split and launch fullscreen
@@ -226,20 +229,40 @@
                 // Not in split, enter split now
                 mStarter.enterSplitScreen(mSession.runningTaskId,
                         target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP);
+                deferAppLaunchUntilSplit = true;
             }
         }
 
-        Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
-                ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
-                : null;
-        if (isTask) {
-            mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
-        } else if (isShortcut) {
-            mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
-                    dragData.getStringExtra(EXTRA_SHORTCUT_ID),
-                    opts, dragData.getParcelableExtra(EXTRA_USER));
+        final Runnable startAppRunnable = () -> {
+            Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+                    ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
+                    : null;
+            if (isTask) {
+                mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
+            } else if (isShortcut) {
+                mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
+                        dragData.getStringExtra(EXTRA_SHORTCUT_ID),
+                        opts, dragData.getParcelableExtra(EXTRA_USER));
+            } else {
+                mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+            }
+        };
+        if (deferAppLaunchUntilSplit) {
+            // TODO(b/169894807): The enterSplitScreen() call above will trigger the current task
+            // into split, and we should wait for home and other tasks to be moved to
+            // split-secondary before trying to launch the new secondary task.  This can be removed
+            // once we have app-pairs.
+            mSplitScreen.registerInSplitScreenListener(new Consumer<Boolean>() {
+                @Override
+                public void accept(Boolean inSplit) {
+                    if (inSplit) {
+                        startAppRunnable.run();
+                        mSplitScreen.unregisterInSplitScreenListener(this);
+                    }
+                }
+            });
         } else {
-            mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+            startAppRunnable.run();
         }
     }
 
@@ -274,7 +297,7 @@
          * Updates the session data based on the current state of the system.
          */
         void update() {
-            final ClipDescription description = mInitialDragData.getDescription();
+
             try {
                 List<ActivityManager.RunningTaskInfo> tasks =
                         mIActivityTaskManager.getFilteredTasks(1,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index fa857cdd..5b7531c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -135,17 +135,25 @@
         // visibility of the current region
         DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
                 (int) event.getX(), (int) event.getY());
-        if (target != null && mCurrentTarget != target) {
+        if (mCurrentTarget != target) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
-            Interpolator boundsInterpolator = FAST_OUT_SLOW_IN;
-            if (mCurrentTarget == null) {
+            if (target == null) {
+                // Animating to no target
+                mDropOutline.startVisibilityAnimation(false, LINEAR);
+                Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
+                finalBounds.inset(mDisplayMargin, mDisplayMargin);
+                mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+            } else if (mCurrentTarget == null) {
+                // Animating to first target
                 mDropOutline.startVisibilityAnimation(true, LINEAR);
                 Rect initialBounds = new Rect(target.drawRegion);
                 initialBounds.inset(mDisplayMargin, mDisplayMargin);
                 mDropOutline.setRegionBounds(initialBounds);
-                boundsInterpolator = LINEAR_OUT_SLOW_IN;
+                mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+            } else {
+                // Bounds change
+                mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
             }
-            mDropOutline.startBoundsAnimation(target.drawRegion, boundsInterpolator);
             mCurrentTarget = target;
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 7d039d4..f84936e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -19,6 +19,7 @@
 import static android.os.UserHandle.USER_CURRENT;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.om.IOverlayManager;
 import android.content.om.OverlayInfo;
@@ -38,6 +39,8 @@
 
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
 
 import java.io.PrintWriter;
@@ -164,7 +167,8 @@
      */
     @Nullable
     public static OneHandedController create(
-            Context context, DisplayController displayController) {
+            Context context, DisplayController displayController,
+            TaskStackListenerImpl taskStackListener) {
         if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
             Slog.w(TAG, "Device doesn't support OneHanded feature");
             return null;
@@ -181,7 +185,7 @@
         IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
                 ServiceManager.getService(Context.OVERLAY_SERVICE));
         return new OneHandedController(context, displayController, organizer, touchHandler,
-                tutorialHandler, gestureHandler, overlayManager);
+                tutorialHandler, gestureHandler, overlayManager, taskStackListener);
     }
 
     @VisibleForTesting
@@ -191,7 +195,8 @@
             OneHandedTouchHandler touchHandler,
             OneHandedTutorialHandler tutorialHandler,
             OneHandedGestureHandler gestureHandler,
-            IOverlayManager overlayManager) {
+            IOverlayManager overlayManager,
+            TaskStackListenerImpl taskStackListener) {
         mContext = context;
         mDisplayAreaOrganizer = displayAreaOrganizer;
         mDisplayController = displayController;
@@ -216,6 +221,19 @@
         setupTimeoutListener();
         setupGesturalOverlay();
         updateSettings();
+
+        taskStackListener.addListener(
+                new TaskStackListenerCallback() {
+                    @Override
+                    public void onTaskCreated(int taskId, ComponentName componentName) {
+                        stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+                    }
+
+                    @Override
+                    public void onTaskMovedToFront(int taskId) {
+                        stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+                    }
+                });
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 8d5da1a..9fa222a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -81,30 +81,6 @@
     }
 
     /**
-     * Called whenever an Activity is moved to the pinned stack from another stack.
-     */
-    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() {
@@ -132,12 +108,6 @@
     }
 
     /**
-     * Called when task stack changed.
-     */
-    default void onTaskStackChanged() {
-    }
-
-    /**
      * Resize the Pip to the appropriate size for the input state.
      *
      * @param state In Pip state also used to determine the new size for the Pip.
@@ -214,4 +184,11 @@
     default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
         return;
     }
+
+    /**
+     * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used
+     * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed
+     * PiP and the Back-from-Edge gesture.
+     */
+    default void setPipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
index 7c69c0c..ca16cfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
@@ -58,13 +58,6 @@
     private int mDefaultStackGravity;
     private int mDefaultMinSize;
     private Point mScreenEdgeInsets;
-    private int mCurrentMinSize;
-    private Size mOverrideMinimalSize;
-
-    private boolean mIsImeShowing;
-    private int mImeHeight;
-    private boolean mIsShelfShowing;
-    private int mShelfHeight;
 
     public PipBoundsHandler(Context context, @NonNull PipBoundsState pipBoundsState) {
         mPipBoundsState = pipBoundsState;
@@ -74,6 +67,7 @@
         // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
         // triggers a configuration change and the resources to be reloaded.
         mPipBoundsState.setAspectRatio(mDefaultAspectRatio);
+        mPipBoundsState.setMinEdgeSize(mDefaultMinSize);
     }
 
     /**
@@ -87,7 +81,6 @@
                 com.android.internal.R.integer.config_defaultPictureInPictureGravity);
         mDefaultMinSize = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
-        mCurrentMinSize = mDefaultMinSize;
         final String screenEdgeInsetsDpString = res.getString(
                 com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
         final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
@@ -103,37 +96,6 @@
     }
 
     /**
-     * Update the Min edge size for {@link PipSnapAlgorithm} to calculate corresponding bounds
-     * @param minEdgeSize
-     */
-    public void setMinEdgeSize(int minEdgeSize) {
-        mCurrentMinSize = minEdgeSize;
-    }
-
-    /**
-     * Sets both shelf visibility and its height if applicable.
-     * @return {@code true} if the internal shelf state is changed, {@code false} otherwise.
-     */
-    public boolean setShelfHeight(boolean shelfVisible, int shelfHeight) {
-        final boolean shelfShowing = shelfVisible && shelfHeight > 0;
-        if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) {
-            return false;
-        }
-
-        mIsShelfShowing = shelfVisible;
-        mShelfHeight = shelfHeight;
-        return true;
-    }
-
-    /**
-     * Responds to IPinnedStackListener on IME visibility change.
-     */
-    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-        mIsImeShowing = imeVisible;
-        mImeHeight = imeHeight;
-    }
-
-    /**
      * Responds to IPinnedStackListener on movement bounds change.
      * Note that both inset and normal bounds will be calculated here rather than in the caller.
      */
@@ -166,42 +128,28 @@
         reloadResources(context);
     }
 
-    /**
-     * See {@link #getDestinationBounds(Rect, Size, boolean)}
-     */
-    public Rect getDestinationBounds(Rect bounds, Size minimalSize) {
-        return getDestinationBounds(bounds, minimalSize, false /* useCurrentMinEdgeSize */);
-    }
+    /** Returns the destination bounds to place the PIP window on entry. */
+    public Rect getEntryDestinationBounds() {
+        final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState();
+        final boolean shouldRestoreReentryBounds = reentryState != null;
 
-    /**
-     * @return {@link Rect} of the destination PiP window bounds.
-     */
-    public Rect getDestinationBounds(Rect bounds, Size minimalSize, boolean useCurrentMinEdgeSize) {
-        boolean isReentryBounds = false;
-        final Rect destinationBounds;
-        if (bounds == null) {
-            // Calculating initial entry bounds
-            final PipBoundsState.PipReentryState state = mPipBoundsState.getReentryState();
+        final Rect destinationBounds = shouldRestoreReentryBounds
+                ? getDefaultBounds(reentryState.getSnapFraction(), reentryState.getSize())
+                : getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
 
-            final Rect defaultBounds;
-            if (state != null) {
-                // Restore to reentry bounds.
-                defaultBounds = getDefaultBounds(state.getSnapFraction(), state.getSize());
-                isReentryBounds = true;
-            } else {
-                // Get actual default bounds.
-                defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
-                mOverrideMinimalSize = minimalSize;
-            }
-
-            destinationBounds = new Rect(defaultBounds);
-        } else {
-            // Just adjusting bounds (e.g. on aspect ratio changed).
-            destinationBounds = new Rect(bounds);
-        }
         if (isValidPictureInPictureAspectRatio(mPipBoundsState.getAspectRatio())) {
             transformBoundsToAspectRatio(destinationBounds, mPipBoundsState.getAspectRatio(),
-                    useCurrentMinEdgeSize, isReentryBounds);
+                    false /* useCurrentMinEdgeSize */, shouldRestoreReentryBounds);
+        }
+        return destinationBounds;
+    }
+
+    /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
+    public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
+        final Rect destinationBounds = new Rect(currentBounds);
+        if (isValidPictureInPictureAspectRatio(newAspectRatio)) {
+            transformBoundsToAspectRatio(destinationBounds, newAspectRatio,
+                    true /* useCurrentMinEdgeSize */, false /* isReentryBounds */);
         }
         return destinationBounds;
     }
@@ -307,66 +255,55 @@
     }
 
     /**
-     * Sets the current bound with the currently store aspect ratio.
-     * @param stackBounds
-     */
-    public void transformBoundsToAspectRatio(Rect stackBounds) {
-        transformBoundsToAspectRatio(stackBounds, mPipBoundsState.getAspectRatio(),
-                true /* useCurrentMinEdgeSize */, true /* useCurrentSize */);
-    }
-
-    /**
      * Set the current bounds (or the default bounds if there are no current bounds) with the
      * specified aspect ratio.
      */
-    private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
+    public void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
             boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
         // Save the snap fraction and adjust the size based on the new aspect ratio.
         final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
                 getMovementBounds(stackBounds), mPipBoundsState.getStashedState());
-        final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
+
+        final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
         final Size size;
         if (useCurrentMinEdgeSize || useCurrentSize) {
+            // The default minimum edge size, or the override min edge size if set.
+            final int defaultMinEdgeSize = overrideMinSize == null ? mDefaultMinSize
+                    : mPipBoundsState.getOverrideMinEdgeSize();
+            final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize()
+                    : defaultMinEdgeSize;
+            // Use the existing size but adjusted to the aspect ratio and min edge size.
             size = mSnapAlgorithm.getSizeForAspectRatio(
                     new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
         } else {
-            final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
-            size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
-                    displayInfo.logicalWidth, displayInfo.logicalHeight);
+            if (overrideMinSize != null) {
+                // The override minimal size is set, use that as the default size making sure it's
+                // adjusted to the aspect ratio.
+                size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio);
+            } else {
+                // Calculate the default size using the display size and default min edge size.
+                final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
+                size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
+                        displayInfo.logicalWidth, displayInfo.logicalHeight);
+            }
         }
 
         final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
         final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
         stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
-        // apply the override minimal size if applicable, this minimal size is specified by app
-        if (mOverrideMinimalSize != null) {
-            transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize);
-        }
         mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
     }
 
-    /**
-     * Transforms a given bounds to meet the minimal size constraints.
-     * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}.
-     */
-    private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio,
-            Size minimalSize) {
-        if (minimalSize == null) return;
-        final Size adjustedMinimalSize;
-        final float minimalSizeAspectRatio =
-                minimalSize.getWidth() / (float) minimalSize.getHeight();
-        if (minimalSizeAspectRatio > aspectRatio) {
-            // minimal size is wider, fixed the width and increase the height
-            adjustedMinimalSize = new Size(
-                    minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio));
+    /** Adjusts the given size to conform to the given aspect ratio. */
+    private Size adjustSizeToAspectRatio(@NonNull Size size, float aspectRatio) {
+        final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
+        if (sizeAspectRatio > aspectRatio) {
+            // Size is wider, fix the width and increase the height
+            return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
         } else {
-            adjustedMinimalSize = new Size(
-                    (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight());
+            // Size is taller, fix the height and adjust the width.
+            return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
         }
-        final Rect containerBounds = new Rect(stackBounds);
-        Gravity.apply(mDefaultStackGravity,
-                adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(),
-                containerBounds, stackBounds);
     }
 
     /**
@@ -383,12 +320,22 @@
             final Rect insetBounds = new Rect();
             getInsetBounds(insetBounds);
             final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
-            size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
-                    mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
-            Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
-                    0, Math.max(mIsImeShowing ? mImeHeight : 0,
-                            mIsShelfShowing ? mShelfHeight : 0),
-                    defaultBounds);
+            final Size defaultSize;
+            final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
+            if (overrideMinSize != null) {
+                // The override minimal size is set, use that as the default size making sure it's
+                // adjusted to the aspect ratio.
+                defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio);
+            } else {
+                // Calculate the default size using the display size and default min edge size.
+                defaultSize = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
+                        mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
+            }
+            Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(),
+                    insetBounds, 0, Math.max(
+                            mPipBoundsState.isImeShowing() ? mPipBoundsState.getImeHeight() : 0,
+                            mPipBoundsState.isShelfShowing()
+                                    ? mPipBoundsState.getShelfHeight() : 0), defaultBounds);
         }
         return defaultBounds;
     }
@@ -423,7 +370,8 @@
 
         // Apply the movement bounds adjustments based on the current state.
         mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
-                (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
+                (adjustForIme && mPipBoundsState.isImeShowing())
+                        ? mPipBoundsState.getImeHeight() : 0);
         return movementBounds;
     }
 
@@ -443,6 +391,10 @@
         mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
     }
 
+    public int getDefaultMinSize() {
+        return mDefaultMinSize;
+    }
+
     /**
      * @return the pixels for a given dp value.
      */
@@ -460,10 +412,6 @@
         pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio);
         pw.println(innerPrefix + "mMaxAspectRatio=" + mMaxAspectRatio);
         pw.println(innerPrefix + "mDefaultStackGravity=" + mDefaultStackGravity);
-        pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
-        pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
-        pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
-        pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
         pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 57867d0..78f7e25 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -33,6 +33,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.function.BiConsumer;
 
 /**
  * Singleton source of truth for the current state of PIP bounds.
@@ -61,7 +62,18 @@
     private ComponentName mLastPipComponentName;
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
     private final DisplayLayout mDisplayLayout = new DisplayLayout();
+    /** The current minimum edge size of PIP. */
+    private int mMinEdgeSize;
+    /** The preferred minimum (and default) size specified by apps. */
+    private Size mOverrideMinSize;
     private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState();
+    private boolean mIsImeShowing;
+    private int mImeHeight;
+    private boolean mIsShelfShowing;
+    private int mShelfHeight;
+
+    private Runnable mOnMinimalSizeChangeCallback;
+    private BiConsumer<Boolean, Integer> mOnShelfVisibilityChangeCallback;
 
     public PipBoundsState(Context context) {
         mContext = context;
@@ -203,10 +215,95 @@
         mPipReentryState = null;
     }
 
+    /** Set the PIP minimum edge size. */
+    public void setMinEdgeSize(int minEdgeSize) {
+        mMinEdgeSize = minEdgeSize;
+    }
+
+    /** Returns the PIP's current minimum edge size. */
+    public int getMinEdgeSize() {
+        return mMinEdgeSize;
+    }
+
+    /**
+     * Sets the preferred size of PIP as specified by the activity in PIP mode.
+     */
+    public void setOverrideMinSize(Size overrideMinSize) {
+        final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize);
+        mOverrideMinSize = overrideMinSize;
+        if (changed && mOnMinimalSizeChangeCallback != null) {
+            mOnMinimalSizeChangeCallback.run();
+        }
+    }
+
+    /** Returns the preferred minimal size specified by the activity in PIP. */
+    public Size getOverrideMinSize() {
+        return mOverrideMinSize;
+    }
+
+    /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
+    public int getOverrideMinEdgeSize() {
+        if (mOverrideMinSize == null) return 0;
+        return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight());
+    }
+
     public AnimatingBoundsState getAnimatingBoundsState() {
         return mAnimatingBoundsState;
     }
 
+    /** Set whether the IME is currently showing and its height. */
+    public void setImeVisibility(boolean imeShowing, int imeHeight) {
+        mIsImeShowing = imeShowing;
+        mImeHeight = imeHeight;
+    }
+
+    /** Returns whether the IME is currently showing. */
+    public boolean isImeShowing() {
+        return mIsImeShowing;
+    }
+
+    /** Returns the IME height. */
+    public int getImeHeight() {
+        return mImeHeight;
+    }
+
+    /** Set whether the shelf is showing and its height. */
+    public void setShelfVisibility(boolean showing, int height) {
+        final boolean shelfShowing = showing && height > 0;
+        if (shelfShowing == mIsShelfShowing && height == mShelfHeight) {
+            return;
+        }
+
+        mIsShelfShowing = showing;
+        mShelfHeight = height;
+        if (mOnShelfVisibilityChangeCallback != null) {
+            mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight);
+        }
+    }
+
+    /** Returns whether the shelf is currently showing. */
+    public boolean isShelfShowing() {
+        return mIsShelfShowing;
+    }
+
+    /** Returns the shelf height. */
+    public int getShelfHeight() {
+        return mShelfHeight;
+    }
+
+    /**
+     * Registers a callback when the minimal size of PIP that is set by the app changes.
+     */
+    public void setOnMinimalSizeChangeCallback(Runnable onMinimalSizeChangeCallback) {
+        mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback;
+    }
+
+    /** Set a callback to be notified when the shelf visibility changes. */
+    public void setOnShelfVisibilityChangeCallback(
+            BiConsumer<Boolean, Integer> onShelfVisibilityChangeCallback) {
+        mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
+    }
+
     /** Source of truth for the current animation bounds of PIP. */
     public static class AnimatingBoundsState {
         /** The bounds used when PIP is being dragged or animated. */
@@ -298,6 +395,12 @@
         pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
         pw.println(innerPrefix + "mStashedState=" + mStashedState);
         pw.println(innerPrefix + "mStashOffset=" + mStashOffset);
+        pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize);
+        pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
+        pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
+        pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
+        pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
+        pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
         if (mPipReentryState == null) {
             pw.println(innerPrefix + "mPipReentryState=null");
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b2f4b55..a095fb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -339,10 +339,8 @@
             PictureInPictureParams pictureInPictureParams) {
         mShouldIgnoreEnteringPipTransition = true;
         sendOnPipTransitionStarted(componentName, TRANSITION_DIRECTION_TO_PIP);
-        mPipBoundsState.setLastPipComponentName(componentName);
-        mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(pictureInPictureParams));
-        return mPipBoundsHandler.getDestinationBounds(null /* bounds */,
-                getMinimalSize(activityInfo));
+        setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
+        return mPipBoundsHandler.getEntryDestinationBounds();
     }
 
     /**
@@ -356,6 +354,13 @@
         }
     }
 
+    private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
+            ActivityInfo activityInfo) {
+        mPipBoundsState.setLastPipComponentName(componentName);
+        mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(params));
+        mPipBoundsState.setOverrideMinSize(getMinimalSize(activityInfo));
+    }
+
     /**
      * Expands PiP to the previous bounds, this is done in two phases using
      * {@link WindowContainerTransaction}
@@ -483,7 +488,8 @@
         mLeash = leash;
         mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
         mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
-        mPipBoundsState.setLastPipComponentName(mTaskInfo.topActivity);
+        setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams,
+                mTaskInfo.topActivityInfo);
 
         mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
         mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
@@ -495,7 +501,9 @@
             mOnDisplayIdChangeCallback.accept(info.displayId);
         }
 
-        mMenuActivityController.onTaskAppeared();
+        if (mMenuActivityController != null) {
+            mMenuActivityController.onTaskAppeared();
+        }
 
         if (mShouldIgnoreEnteringPipTransition) {
             final Rect destinationBounds = mPipBoundsState.getBounds();
@@ -520,9 +528,7 @@
             return;
         }
 
-        mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(mPictureInPictureParams));
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */,
-                getMinimalSize(mTaskInfo.topActivityInfo));
+        final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
         final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
 
@@ -668,22 +674,24 @@
         mPictureInPictureParams = null;
         mState = State.UNDEFINED;
         mPipUiEventLoggerLogger.setTaskInfo(null);
-        mMenuActivityController.onTaskVanished();
+        if (mMenuActivityController != null) {
+            mMenuActivityController.onTaskVanished();
+        }
     }
 
     @Override
     public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
         Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
         mPipBoundsState.setLastPipComponentName(info.topActivity);
+        mPipBoundsState.setOverrideMinSize(getMinimalSize(info.topActivityInfo));
         final PictureInPictureParams newParams = info.pictureInPictureParams;
         if (newParams == null || !applyPictureInPictureParams(newParams)) {
             Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
             return;
         }
-        // Aspect ratio changed, re-calculate destination bounds.
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                mPipBoundsState.getBounds(), getMinimalSize(info.topActivityInfo),
-                true /* userCurrentMinEdgeSize */);
+        // Aspect ratio changed, re-calculate bounds if valid.
+        final Rect destinationBounds = mPipBoundsHandler.getAdjustedDestinationBounds(
+                mPipBoundsState.getBounds(), mPipBoundsState.getAspectRatio());
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
         scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration,
                 null /* updateBoundsCallback */);
@@ -697,8 +705,7 @@
     @Override
     public void onFixedRotationFinished(int displayId) {
         if (mShouldDeferEnteringPip && mState.isInPip()) {
-            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
+            final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
             // schedule a regular animation to ensure all the callbacks are still being sent
             enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */);
         }
@@ -773,8 +780,7 @@
             return;
         }
 
-        final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */,
-                getMinimalSize(mTaskInfo.topActivityInfo));
+        final Rect newDestinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
         if (newDestinationBounds.equals(currentDestinationBounds)) return;
         if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
             animator.updateEndValue(newDestinationBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 6e1fc83..8e48229 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -16,12 +16,15 @@
 
 package com.android.wm.shell.pip.phone;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.PictureInPictureParams;
 import android.app.RemoteAction;
 import android.content.ComponentName;
@@ -32,9 +35,12 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.IPinnedStackController;
+import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
@@ -44,13 +50,17 @@
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.PipInputConsumer;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsHandler;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUtils;
 
 import java.io.PrintWriter;
 import java.util.function.Consumer;
@@ -63,22 +73,22 @@
 
     private Context mContext;
     private ShellExecutor mMainExecutor;
+    private DisplayController mDisplayController;
+    private PipInputConsumer mPipInputConsumer;
+    private WindowManagerShellWrapper mWindowManagerShellWrapper;
+    private PipAppOpsListener mAppOpsListener;
+    private PipMediaController mMediaController;
+    private PipBoundsHandler mPipBoundsHandler;
+    private PipBoundsState mPipBoundsState;
+    private PipTouchHandler mTouchHandler;
 
     private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
     private final Rect mTmpInsetBounds = new Rect();
     private final Rect mTmpNormalBounds = new Rect();
     protected final Rect mReentryBounds = new Rect();
 
-    private DisplayController mDisplayController;
-    private PipAppOpsListener mAppOpsListener;
-    private PipBoundsHandler mPipBoundsHandler;
-    private @NonNull PipBoundsState mPipBoundsState;
-    private PipMediaController mMediaController;
-    private PipTouchHandler mTouchHandler;
-    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
-    private WindowManagerShellWrapper mWindowManagerShellWrapper;
-
     private boolean mIsInFixedRotation;
+    private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
 
     protected PipMenuActivityController mMenuController;
     protected PipTaskOrganizer mPipTaskOrganizer;
@@ -115,8 +125,8 @@
             // not during the fixed rotation. In fixed rotation case, app is about to enter PiP
             // and we need the offsets preserved to calculate the destination bounds.
             if (!mIsInFixedRotation) {
-                mPipBoundsHandler.setShelfHeight(false, 0);
-                mPipBoundsHandler.onImeVisibilityChanged(false, 0);
+                mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */);
+                mPipBoundsState.setImeVisibility(false /* showing */, 0 /* height */);
                 mTouchHandler.onShelfVisibilityChanged(false, 0);
                 mTouchHandler.onImeVisibilityChanged(false, 0);
             }
@@ -158,7 +168,7 @@
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mMainExecutor.execute(() -> {
-                mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+                mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
                 mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
             });
         }
@@ -221,6 +231,7 @@
             PipTaskOrganizer pipTaskOrganizer,
             PipTouchHandler pipTouchHandler,
             WindowManagerShellWrapper windowManagerShellWrapper,
+            TaskStackListenerImpl taskStackListener,
             ShellExecutor mainExecutor
     ) {
         // Ensure that we are the primary user's SystemUI.
@@ -236,19 +247,39 @@
         mPipBoundsState = pipBoundsState;
         mPipTaskOrganizer = pipTaskOrganizer;
         mMainExecutor = mainExecutor;
+        mMediaController = pipMediaController;
+        mMenuController = pipMenuActivityController;
+        mTouchHandler = pipTouchHandler;
+        mAppOpsListener = pipAppOpsListener;
+        mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
+                INPUT_CONSUMER_PIP);
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> {
             final DisplayInfo newDisplayInfo = new DisplayInfo();
             displayController.getDisplay(displayId).getDisplayInfo(newDisplayInfo);
             mPipBoundsState.setDisplayInfo(newDisplayInfo);
             updateMovementBounds(null /* toBounds */, false /* fromRotation */,
-                    false /* fromImeAdjustment */, false /* fromShelfAdustment */,
+                    false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
                     null /* wct */);
         });
-        mMediaController = pipMediaController;
-        mMenuController = pipMenuActivityController;
-        mTouchHandler = pipTouchHandler;
-        mAppOpsListener = pipAppOpsListener;
+        mPipBoundsState.setOnMinimalSizeChangeCallback(
+                () -> {
+                    // The minimal size drives the normal bounds, so they need to be recalculated.
+                    updateMovementBounds(null /* toBounds */, false /* fromRotation */,
+                            false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
+                            null /* wct */);
+                });
+        mPipBoundsState.setOnShelfVisibilityChangeCallback((isShowing, height) -> {
+            mTouchHandler.onShelfVisibilityChanged(isShowing, height);
+            updateMovementBounds(mPipBoundsState.getBounds(),
+                    false /* fromRotation */, false /* fromImeAdjustment */,
+                    true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
+        });
+        if (mTouchHandler != null) {
+            // Register the listener for input consumer touch events. Only for Phone
+            mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent);
+            mPipInputConsumer.setRegistrationListener(mTouchHandler::onRegistrationChanged);
+        }
         displayController.addDisplayChangingController(mRotationController);
         displayController.addDisplayWindowListener(mFixedRotationListener);
 
@@ -263,6 +294,56 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to register pinned stack listener", e);
         }
+
+        try {
+            ActivityTaskManager.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.
+                mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+            }
+        } catch (RemoteException | UnsupportedOperationException e) {
+            Log.e(TAG, "Failed to register pinned stack listener", e);
+            e.printStackTrace();
+        }
+
+        // Handle for system task stack changes.
+        taskStackListener.addListener(
+                new TaskStackListenerCallback() {
+                    @Override
+                    public void onActivityPinned(String packageName, int userId, int taskId,
+                            int stackId) {
+                        mMainExecutor.execute(() -> {
+                            mTouchHandler.onActivityPinned();
+                            mMediaController.onActivityPinned();
+                            mAppOpsListener.onActivityPinned(packageName);
+                        });
+                        mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+                    }
+
+                    @Override
+                    public void onActivityUnpinned() {
+                        final Pair<ComponentName, Integer> topPipActivityInfo =
+                                PipUtils.getTopPipActivity(mContext);
+                        final ComponentName topActivity = topPipActivityInfo.first;
+                        mMainExecutor.execute(() -> {
+                            mTouchHandler.onActivityUnpinned(topActivity);
+                            mAppOpsListener.onActivityUnpinned();
+                        });
+                        mPipInputConsumer.unregisterInputConsumer();
+                    }
+
+                    @Override
+                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                        if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
+                            return;
+                        }
+                        mTouchHandler.getMotionHelper().expandLeavePip(
+                                clearedTask /* skipAnimation */);
+                    }
+                });
     }
 
     @Override
@@ -273,33 +354,6 @@
     }
 
     @Override
-    public void onActivityPinned(String packageName) {
-        mMainExecutor.execute(() -> {
-            mTouchHandler.onActivityPinned();
-            mMediaController.onActivityPinned();
-            mAppOpsListener.onActivityPinned(packageName);
-        });
-    }
-
-    @Override
-    public void onActivityUnpinned(ComponentName topActivity) {
-        mMainExecutor.execute(() -> {
-            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() {
         mMainExecutor.execute(() -> {
             mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
@@ -365,13 +419,7 @@
 
     private void setShelfHeightLocked(boolean visible, int height) {
         final int shelfHeight = visible ? height : 0;
-        final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight);
-        if (changed) {
-            mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight);
-            updateMovementBounds(mPipBoundsState.getBounds(),
-                    false /* fromRotation */, false /* fromImeAdjustment */,
-                    true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
-        }
+        mPipBoundsState.setShelfVisibility(visible, shelfHeight);
     }
 
     @Override
@@ -424,6 +472,16 @@
         mReentryBounds.set(reentryBounds);
     }
 
+    /**
+     * Set a listener to watch out for PiP bounds. This is mostly used by SystemUI's
+     * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
+     */
+    @Override
+    public void setPipExclusionBoundsChangeListener(
+            Consumer<Rect> pipExclusionBoundsChangeListener) {
+        mTouchHandler.setPipExclusionBoundsChangeListener(pipExclusionBoundsChangeListener);
+    }
+
     @Override
     public void onPipTransitionFinished(ComponentName activity, int direction) {
         onPipTransitionFinishedOrCanceled(direction);
@@ -467,6 +525,7 @@
         mPipBoundsHandler.dump(pw, innerPrefix);
         mPipTaskOrganizer.dump(pw, innerPrefix);
         mPipBoundsState.dump(pw, innerPrefix);
+        mPipInputConsumer.dump(pw, innerPrefix);
     }
 
     /**
@@ -476,17 +535,16 @@
     public static PipController create(Context context, DisplayController displayController,
             PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
             PipBoundsState pipBoundsState, PipMediaController pipMediaController,
-            PipMenuActivityController pipMenuActivityController,
-            PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler,
-            WindowManagerShellWrapper windowManagerShellWrapper,
-            ShellExecutor mainExecutor) {
+            PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+            PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
+            TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
         if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             Slog.w(TAG, "Device doesn't support Pip feature");
             return null;
         }
 
         return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler,
-                pipBoundsState, pipMediaController, pipMenuActivityController,
-                pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper, mainExecutor);
+                pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
+                pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 2e3db06..d211d65 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -262,8 +262,7 @@
                     .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig)
                     .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig);
 
-            startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */,
-                    false /* dismiss */);
+            startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */);
         }
     }
 
@@ -292,7 +291,7 @@
                 .spring(FloatProperties.RECT_HEIGHT, desiredHeight, mSpringConfig)
                 .withEndActions(after);
 
-        startBoundsAnimator(destinationX, destinationY, false);
+        startBoundsAnimator(destinationX, destinationY);
     }
 
     /** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */
@@ -364,21 +363,24 @@
      * Flings the PiP to the closest snap target.
      */
     void flingToSnapTarget(
-            float velocityX, float velocityY, @Nullable Runnable endAction) {
-        movetoTarget(velocityX, velocityY, endAction, false /* isStash */);
+            float velocityX, float velocityY, @Nullable Runnable postBoundsUpdateCallback) {
+        movetoTarget(velocityX, velocityY, postBoundsUpdateCallback, false /* isStash */);
     }
 
     /**
      * Stash PiP to the closest edge.
      */
     void stashToEdge(
-            float velocityX, float velocityY, @Nullable Runnable endAction) {
+            float velocityX, float velocityY, @Nullable Runnable postBoundsUpdateCallback) {
         mPipBoundsState.setStashed(velocityX < 0 ? STASH_TYPE_LEFT : STASH_TYPE_RIGHT);
-        movetoTarget(velocityX, velocityY, endAction, true /* isStash */);
+        movetoTarget(velocityX, velocityY, postBoundsUpdateCallback, true /* isStash */);
     }
 
     private void movetoTarget(
-            float velocityX, float velocityY, @Nullable Runnable endAction, boolean isStash) {
+            float velocityX,
+            float velocityY,
+            @Nullable Runnable postBoundsUpdateCallback,
+            boolean isStash) {
         // If we're flinging to a snap target now, we're not springing to catch up to the touch
         // location now.
         mSpringingToTouch = false;
@@ -390,8 +392,7 @@
                         FloatProperties.RECT_X, velocityX, isStash ? mStashConfigX : mFlingConfigX,
                         mSpringConfig, true /* flingMustReachMinOrMax */)
                 .flingThenSpring(
-                        FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig)
-                .withEndActions(endAction);
+                        FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig);
 
         final float leftEdge = isStash
                 ? mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width()
@@ -407,7 +408,7 @@
                 PhysicsAnimator.estimateFlingEndValue(startValueY, velocityY, mFlingConfigY);
 
         startBoundsAnimator(xEndValue /* toX */, estimatedFlingYEndValue /* toY */,
-                false /* dismiss */);
+                postBoundsUpdateCallback);
     }
 
     /**
@@ -423,8 +424,7 @@
         mTemporaryBoundsPhysicsAnimator
                 .spring(FloatProperties.RECT_X, bounds.left, springConfig)
                 .spring(FloatProperties.RECT_Y, bounds.top, springConfig);
-        startBoundsAnimator(bounds.left /* toX */, bounds.top /* toY */,
-                false /* dismiss */);
+        startBoundsAnimator(bounds.left /* toX */, bounds.top /* toY */);
     }
 
     /**
@@ -440,8 +440,7 @@
                 .withEndActions(this::dismissPip);
 
         startBoundsAnimator(
-                getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */,
-                true /* dismiss */);
+                getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */);
 
         mDismissalPending = false;
     }
@@ -516,14 +515,21 @@
                 mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset());
     }
 
+    private void startBoundsAnimator(float toX, float toY) {
+        startBoundsAnimator(toX, toY, null /* postBoundsUpdateCallback */);
+    }
+
     /**
      * Starts the physics animator which will update the animated PIP bounds using physics
      * animations, as well as the TimeAnimator which will apply those bounds to PIP.
      *
      * This will also add end actions to the bounds animator that cancel the TimeAnimator and update
      * the 'real' bounds to equal the final animated bounds.
+     *
+     * If one wishes to supply a callback after all the 'real' bounds update has happened,
+     * pass @param postBoundsUpdateCallback.
      */
-    private void startBoundsAnimator(float toX, float toY, boolean dismiss) {
+    private void startBoundsAnimator(float toX, float toY, Runnable postBoundsUpdateCallback) {
         if (!mSpringingToTouch) {
             cancelPhysicsAnimation();
         }
@@ -535,9 +541,16 @@
                 (int) toY + getBounds().height()));
 
         if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
-            mTemporaryBoundsPhysicsAnimator
-                    .addUpdateListener(mResizePipUpdateListener)
-                    .withEndActions(this::onBoundsPhysicsAnimationEnd);
+            if (postBoundsUpdateCallback != null) {
+                mTemporaryBoundsPhysicsAnimator
+                        .addUpdateListener(mResizePipUpdateListener)
+                        .withEndActions(this::onBoundsPhysicsAnimationEnd,
+                                postBoundsUpdateCallback);
+            } else {
+                mTemporaryBoundsPhysicsAnimator
+                        .addUpdateListener(mResizePipUpdateListener)
+                        .withEndActions(this::onBoundsPhysicsAnimationEnd);
+            }
         }
 
         mTemporaryBoundsPhysicsAnimator.start();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index f3d8c7b..124683e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -451,7 +451,9 @@
                                 mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
                                 mMinSize.y, mMaxSize, true,
                                 mLastDownBounds.width() > mLastDownBounds.height()));
-                        mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
+                        mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds,
+                                mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+                                true /* useCurrentSize */);
                         mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
                                 null);
                     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9ba4672..ae1dd38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -54,6 +54,8 @@
 import com.android.wm.shell.pip.PipUiEventLogger;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.function.Consumer;
 
 /**
  * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
@@ -78,6 +80,7 @@
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
     private IPinnedStackController mPinnedStackController;
+    private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
 
     private final PipMenuActivityController mMenuController;
     private final AccessibilityManager mAccessibilityManager;
@@ -259,6 +262,11 @@
 
             mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
         }
+        // Reset exclusion to none.
+        if (mPipExclusionBoundsChangeListener != null
+                && mPipExclusionBoundsChangeListener.get() != null) {
+            mPipExclusionBoundsChangeListener.get().accept(new Rect());
+        }
         mPipResizeGestureHandler.onActivityUnpinned();
     }
 
@@ -788,7 +796,7 @@
                 if (mEnableStash
                         && (animatingBounds.right > mPipBoundsState.getDisplayBounds().right
                         || animatingBounds.left < mPipBoundsState.getDisplayBounds().left)) {
-                    mMotionHelper.stashToEdge(vel.x, vel.y, this::flingEndAction /* endAction */);
+                    mMotionHelper.stashToEdge(vel.x, vel.y, this::stashEndAction /* endAction */);
                 } else {
                     mMotionHelper.flingToSnapTarget(vel.x, vel.y,
                             this::flingEndAction /* endAction */);
@@ -829,15 +837,32 @@
             return true;
         }
 
+        private void stashEndAction() {
+            if (mPipExclusionBoundsChangeListener != null
+                    && mPipExclusionBoundsChangeListener.get() != null) {
+                mPipExclusionBoundsChangeListener.get().accept(mPipBoundsState.getBounds());
+            }
+        }
+
         private void flingEndAction() {
             if (mShouldHideMenuAfterFling) {
                 // If the menu is not visible, then we can still be showing the activity for the
                 // dismiss overlay, so just finish it after the animation completes
                 mMenuController.hideMenu();
             }
+            // Reset exclusion to none.
+            if (mPipExclusionBoundsChangeListener != null
+                    && mPipExclusionBoundsChangeListener.get() != null) {
+                mPipExclusionBoundsChangeListener.get().accept(new Rect());
+            }
         }
     }
 
+    void setPipExclusionBoundsChangeListener(Consumer<Rect> pipExclusionBoundsChangeListener) {
+        mPipExclusionBoundsChangeListener = new WeakReference<>(pipExclusionBoundsChangeListener);
+        pipExclusionBoundsChangeListener.accept(mPipBoundsState.getBounds());
+    }
+
     /**
      * Updates the current movement bounds based on whether the menu is currently visible and
      * resized.
@@ -848,8 +873,9 @@
         mMotionHelper.setCurrentMovementBounds(mMovementBounds);
 
         boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
-        mPipBoundsHandler.setMinEdgeSize(
-                isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
+        mPipBoundsState.setMinEdgeSize(
+                isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize
+                        : mPipBoundsHandler.getDefaultMinSize());
     }
 
     private Rect getMovementBounds(Rect curBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 3468b88..fd055d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -44,16 +44,20 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 import android.view.DisplayInfo;
 
 import com.android.wm.shell.R;
 import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsHandler;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -180,7 +184,7 @@
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             mHandler.post(() -> {
-                mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+                mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
                 if (mState == STATE_PIP) {
                     if (mImeVisible != imeVisible) {
                         if (imeVisible) {
@@ -225,6 +229,7 @@
             PipTaskOrganizer pipTaskOrganizer,
             PipMediaController pipMediaController,
             PipNotification pipNotification,
+            TaskStackListenerImpl taskStackListener,
             WindowManagerShellWrapper windowManagerShellWrapper) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
@@ -263,6 +268,27 @@
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
 
+        // Handle for system task stack changes.
+        taskStackListener.addListener(
+                new TaskStackListenerCallback() {
+                    @Override
+                    public void onTaskStackChanged() {
+                        PipController.this.onTaskStackChanged();
+                    }
+
+                    @Override
+                    public void onActivityPinned(String packageName, int userId, int taskId,
+                            int stackId) {
+                        PipController.this.onActivityPinned(packageName);
+                    }
+
+                    @Override
+                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                        PipController.this.onActivityRestartAttempt(task, clearedTask);
+                    }
+                });
+
         // TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
         PipMenuActivity.setPipController(this);
     }
@@ -351,8 +377,7 @@
         resizePinnedStack(STATE_NO_PIP);
     }
 
-    @Override
-    public void onActivityPinned(String packageName) {
+    private void onActivityPinned(String packageName) {
         if (DEBUG) Log.d(TAG, "onActivityPinned()");
 
         RootTaskInfo taskInfo = getPinnedTaskInfo();
@@ -371,11 +396,9 @@
         }
     }
 
-    @Override
-    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+    private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
             boolean clearedTask) {
-        if (task.configuration.windowConfiguration.getWindowingMode()
-                != WINDOWING_MODE_PINNED) {
+        if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
             return;
         }
         if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
@@ -384,8 +407,7 @@
         movePipToFullscreen();
     }
 
-    @Override
-    public void onTaskStackChanged() {
+    private void onTaskStackChanged() {
         if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
 
         if (getState() != STATE_NO_PIP) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index d117673..e55f065 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -27,9 +27,6 @@
  * Interface to engage split screen feature.
  */
 public interface SplitScreen {
-    /** Returns {@code true} if split screen is supported on the device. */
-    boolean isSplitScreenSupported();
-
     /** Called when keyguard showing state changed. */
     void onKeyguardVisibilityChanged(boolean isShowing);
 
@@ -48,15 +45,6 @@
     /** Switch to minimized state if appropriate. */
     void setMinimized(boolean minimized);
 
-    /** Called when there's an activity forced resizable. */
-    void onActivityForcedResizable(String packageName, int taskId, int reason);
-
-    /** Called when there's an activity dismissing split screen. */
-    void onActivityDismissingSplitScreen();
-
-    /** Called when there's an activity launch on secondary display failed. */
-    void onActivityLaunchOnSecondaryDisplayFailed();
-
     /** Called when there's a task undocking. */
     void onUndockingTask();
 
@@ -69,6 +57,9 @@
     /** Registers listener that gets called whenever the existence of the divider changes. */
     void registerInSplitScreenListener(Consumer<Boolean> listener);
 
+    /** Unregisters listener that gets called whenever the existence of the divider changes. */
+    void unregisterInSplitScreenListener(Consumer<Boolean> listener);
+
     /** Registers listener that gets called whenever the split screen bounds changes. */
     void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 341a459..07af289 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -20,9 +20,11 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.content.Context;
@@ -48,12 +50,15 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -81,8 +86,8 @@
     private final WindowManagerProxy mWindowManagerProxy;
     private final TaskOrganizer mTaskOrganizer;
 
-    private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
-            new ArrayList<>();
+    private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
+            = new CopyOnWriteArrayList<>();
     private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
             new ArrayList<>();
 
@@ -107,7 +112,8 @@
     public SplitScreenController(Context context,
             DisplayController displayController, SystemWindows systemWindows,
             DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
-            ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue) {
+            ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
+            TaskStackListenerImpl taskStackListener) {
         mContext = context;
         mDisplayController = displayController;
         mSystemWindows = systemWindows;
@@ -162,6 +168,40 @@
         mWindowManager = new DividerWindowManager(mSystemWindows);
         mDisplayController.addDisplayWindowListener(this);
         // Don't initialize the divider or anything until we get the default display.
+
+        taskStackListener.addListener(
+                new TaskStackListenerCallback() {
+                    @Override
+                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+                        if (!wasVisible || task.getWindowingMode()
+                                != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                                || !mSplits.isSplitScreenSupported()) {
+                            return;
+                        }
+
+                        if (isMinimized()) {
+                            onUndockingTask();
+                        }
+                    }
+
+                    @Override
+                    public void onActivityForcedResizable(String packageName, int taskId,
+                            int reason) {
+                        mForcedResizableController.activityForcedResizable(packageName, taskId,
+                                reason);
+                    }
+
+                    @Override
+                    public void onActivityDismissingDockedStack() {
+                        mForcedResizableController.activityDismissingSplitScreen();
+                    }
+
+                    @Override
+                    public void onActivityLaunchOnSecondaryDisplayFailed() {
+                        mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
+                    }
+                });
     }
 
     void onSplitScreenSupported() {
@@ -173,11 +213,6 @@
     }
 
     @Override
-    public boolean isSplitScreenSupported() {
-        return mSplits.isSplitScreenSupported();
-    }
-
-    @Override
     public void onKeyguardVisibilityChanged(boolean showing) {
         if (!isSplitActive() || mView == null) {
             return;
@@ -404,21 +439,6 @@
     }
 
     @Override
-    public void onActivityForcedResizable(String packageName, int taskId, int reason) {
-        mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
-    }
-
-    @Override
-    public void onActivityDismissingSplitScreen() {
-        mForcedResizableController.activityDismissingSplitScreen();
-    }
-
-    @Override
-    public void onActivityLaunchOnSecondaryDisplayFailed() {
-        mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
-    }
-
-    @Override
     public void onUndockingTask() {
         if (mView != null) {
             mView.onUndockingTask();
@@ -459,6 +479,17 @@
     }
 
     @Override
+    public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
+        synchronized (mDockedStackExistsListeners) {
+            for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
+                if (mDockedStackExistsListeners.get(i) == listener) {
+                    mDockedStackExistsListeners.remove(i);
+                }
+            }
+        }
+    }
+
+    @Override
     public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
         synchronized (mBoundsChangedListeners) {
             mBoundsChangedListeners.add(new WeakReference<>(listener));
@@ -481,9 +512,7 @@
             }
             // Note: The set of running tasks from the system is ordered by recency.
             final RunningTaskInfo topRunningTask = runningTasks.get(0);
-
-            final int activityType = topRunningTask.configuration.windowConfiguration
-                    .getActivityType();
+            final int activityType = topRunningTask.getActivityType();
             if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
                 return false;
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
index 64e9d66..5b2b38b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
@@ -23,7 +23,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
 
 import android.app.ActivityManager.RunningTaskInfo;
@@ -42,6 +41,7 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
     private static final String TAG = "SplitScreenTaskListener";
@@ -106,7 +106,7 @@
                 return;
             }
 
-            final int winMode = getWindowingMode(taskInfo);
+            final int winMode = taskInfo.getWindowingMode();
             if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 ProtoLog.v(WM_SHELL_TASK_ORG,
                         "%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
@@ -283,6 +283,21 @@
                 mSplitScreenController.startEnterSplit();
             }
         } else if (secondaryImpliesMinimize) {
+            // Workaround for b/172686383, we can't rely on the sync bounds change transaction for
+            // the home task to finish before the last updateChildTaskSurface() call even if it's
+            // queued on the sync transaction queue, so ensure that the home task surface is updated
+            // again before we minimize
+            final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
+            mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks,
+                    mSplitScreenController.getSecondaryRoot());
+            for (int i = 0; i < tasks.size(); i++) {
+                final RunningTaskInfo taskInfo = tasks.get(i);
+                final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
+                if (leash != null) {
+                    updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
+                }
+            }
+
             // Both splits are populated but the secondary split has a home/recents stack on top,
             // so enter minimized mode.
             mSplitScreenController.ensureMinimizedSplit();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
index c51bbeb..0307206 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
@@ -120,7 +120,7 @@
         new WindowOrganizer().applyTransaction(t);
     }
 
-    private boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
+    boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
             WindowContainerToken parent) {
         boolean resizable = false;
         List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
@@ -209,8 +209,7 @@
                 continue;
             }
             // Only move fullscreen tasks to split secondary.
-            if (rootTask.configuration.windowConfiguration.getWindowingMode()
-                    != WINDOWING_MODE_FULLSCREEN) {
+            if (rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
                 continue;
             }
             // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
@@ -232,7 +231,7 @@
     }
 
     boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
-        final int atype = ti.configuration.windowConfiguration.getActivityType();
+        final int atype = ti.getActivityType();
         return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 55796da..4ab5c6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -26,6 +26,7 @@
 import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
@@ -60,6 +61,9 @@
             getApplicationLabel(getApplicationInfo(packageName, 0)).toString()
         }
 
+    val ui: UiObject2?
+        get() = uiDevice.findObject(appSelector)
+
     fun launchViaIntent() {
         context.startActivity(openAppIntent)
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
new file mode 100644
index 0000000..33b6902
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.wm.shell.flicker.pip.tv
+
+import android.os.SystemClock
+import androidx.test.filters.RequiresDevice
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Menu on TV.
+ * To run this test: `atest WMShellFlickerTests:TvPipMenuTests`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+class TvPipMenuTests(rotationName: String, rotation: Int)
+    : TvPipTestBase(rotationName, rotation) {
+
+    @Before
+    override fun setUp() {
+        super.setUp()
+        // Launch the app and go to PiP
+        testApp.launchViaIntent()
+        testApp.clickEnterPipButton()
+    }
+
+    @Test
+    fun pipMenu_open() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        val pipMenu = uiDevice.waitForTvPipMenu()
+                ?: fail("Pip notification should have been dismissed")
+
+        assertTrue("Pip menu should be shown fullscreen", pipMenu.isFullscreen(uiDevice))
+
+        testApp.closePipWindow()
+    }
+
+    @Test
+    fun pipMenu_backButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // Pressing the Back key should close the Pip menu
+        uiDevice.pressBack()
+        assertTrue("Pip notification should have closed", uiDevice.waitForTvPipMenuToClose())
+
+        testApp.closePipWindow()
+    }
+
+    @Test
+    fun pipMenu_closeButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // PiP menu should contain the Close button
+        val closeButton = uiDevice.findTvPipMenuCloseButton()
+                ?: fail("\"Close PIP\" button should be shown in Pip menu")
+
+        // Clicking on the Close button should close the app
+        closeButton.click()
+        assertTrue("\"Close PIP\" button should close the PiP", testApp.waitUntilClosed())
+    }
+
+    @Test
+    fun pipMenu_fullscreenButton() {
+        // Pressing the Window key should bring up Pip menu
+        uiDevice.pressWindowKey()
+        assertNotNull("Pip notification should have been dismissed", uiDevice.waitForTvPipMenu())
+
+        // PiP menu should contain the Fullscreen button
+        val fullscreenButton = uiDevice.findTvPipMenuFullscreenButton()
+                ?: fail("\"Full screen\" button should be shown in Pip menu")
+
+        // Clicking on the fullscreen button should return app to the fullscreen mode.
+        // Click, wait for 3 seconds, check the app is fullscreen
+        fullscreenButton.click()
+        SystemClock.sleep(3_000L)
+        assertTrue("\"Full screen\" button should open the app fullscreen",
+                testApp.ui?.isFullscreen(uiDevice) ?: false)
+
+        // Close the app
+        uiDevice.pressBack()
+        testApp.waitUntilClosed()
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> = rotationParams
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
index 1d44658..7a9b33b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -20,7 +20,6 @@
 import android.app.PendingIntent
 import android.os.Bundle
 import android.service.notification.StatusBarNotification
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.NotificationListener.Companion.findNotification
 import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
@@ -32,10 +31,8 @@
 import org.junit.Assert.assertNull
 import org.junit.Assert.assertTrue
 import org.junit.Before
-import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
 /**
@@ -44,7 +41,6 @@
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
 class TvPipNotificationTests(rotationName: String, rotation: Int)
     : TvPipTestBase(rotationName, rotation) {
 
@@ -60,7 +56,6 @@
     @After
     override fun tearDown() {
         stopNotificationListener()
-        testApp.forceStop()
         super.tearDown()
     }
 
@@ -108,7 +103,7 @@
         notification.contentIntent?.send()
             ?: fail("Pip notification should contain `content_intent`")
 
-        assertTrue("Pip menu should have been shown after sending `content_intent`",
+        assertNotNull("Pip menu should have been shown after sending `content_intent`",
                 uiDevice.waitForTvPipMenu())
 
         uiDevice.pressBack()
@@ -156,18 +151,13 @@
         testApp.closePipWindow()
     }
 
-    private fun fail(message: String): Nothing = throw AssertionError(message)
-
     companion object {
         private const val TITLE_MEDIA_SESSION_PLAYING = "TestApp media is playing"
         private const val TITLE_MEDIA_SESSION_PAUSED = "TestApp media is paused"
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<Array<Any>> {
-            val supportedRotations = intArrayOf(Surface.ROTATION_0)
-            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
-        }
+        fun getParams(): Collection<Array<Any>> = rotationParams
     }
 }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 104248c..05f4b0b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -18,6 +18,8 @@
 
 import android.content.pm.PackageManager.FEATURE_LEANBACK
 import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.view.Surface.ROTATION_0
+import android.view.Surface.rotationToString
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.pip.PipTestBase
 import org.junit.After
@@ -40,5 +42,14 @@
 
     @After
     open fun tearDown() {
+        testApp.forceStop()
+    }
+
+    protected fun fail(message: String): Nothing = throw AssertionError(message)
+
+    companion object {
+        @JvmStatic
+        protected val rotationParams: Collection<Array<Any>> =
+                listOf(arrayOf(rotationToString(ROTATION_0), ROTATION_0))
     }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index ac9ab13..d9e6ff3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -16,11 +16,35 @@
 
 package com.android.wm.shell.flicker.pip.tv
 
+import android.view.KeyEvent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
 import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
 
-fun UiDevice.waitForTvPipMenu(): Boolean {
-    return wait(Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "pip_controls")), 3_000) != null
+/** Id of the root view in the com.android.wm.shell.pip.tv.PipMenuActivity */
+private const val TV_PIP_MENU_ROOT_ID = "tv_pip_menu"
+private const val TV_PIP_MENU_CLOSE_BUTTON_ID = "close_button"
+private const val TV_PIP_MENU_FULLSCREEN_BUTTON_ID = "full_button"
+
+private const val WAIT_TIME_MS = 3_000L
+
+private val tvPipMenuSelector = By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_ROOT_ID)
+
+fun UiDevice.pressWindowKey() = pressKeyCode(KeyEvent.KEYCODE_WINDOW)
+
+fun UiDevice.waitForTvPipMenu(): UiObject2? =
+        wait(Until.findObject(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.waitForTvPipMenuToClose(): Boolean = wait(Until.gone(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.findTvPipMenuCloseButton(): UiObject2? = findObject(
+        By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_CLOSE_BUTTON_ID))
+
+fun UiDevice.findTvPipMenuFullscreenButton(): UiObject2? = findObject(
+        By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_FULLSCREEN_BUTTON_ID))
+
+fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
+    height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
new file mode 100644
index 0000000..8842872
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -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.wm.shell.common;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.wm.shell.common.TaskStackListenerImpl}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TaskStackListenerImplTest {
+
+    @Mock
+    private IActivityTaskManager mActivityTaskManager;
+
+    @Mock
+    private TaskStackListenerCallback mCallback;
+
+    @Mock
+    private TaskStackListenerCallback mOtherCallback;
+
+    private TaskStackListenerImpl mImpl;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mImpl = new TaskStackListenerImpl(mActivityTaskManager);
+        mImpl.setHandler(new ProxyToListenerImplHandler(mImpl));
+        mImpl.addListener(mCallback);
+        mImpl.addListener(mOtherCallback);
+    }
+
+    @Test
+    public void testAddRemoveMultipleListeners_ExpectRegisterUnregisterOnce()
+            throws RemoteException {
+        TaskStackListenerImpl impl = new TaskStackListenerImpl(mActivityTaskManager);
+        impl.setHandler(new ProxyToListenerImplHandler(impl));
+        reset(mActivityTaskManager);
+        impl.addListener(mCallback);
+        impl.addListener(mOtherCallback);
+        verify(mActivityTaskManager, times(1)).registerTaskStackListener(any());
+
+        impl.removeListener(mOtherCallback);
+        impl.removeListener(mCallback);
+        verify(mActivityTaskManager, times(1)).unregisterTaskStackListener(any());
+    }
+
+    @Test
+    public void testOnRecentTaskListUpdated() {
+        mImpl.onRecentTaskListUpdated();
+        verify(mCallback).onRecentTaskListUpdated();
+        verify(mOtherCallback).onRecentTaskListUpdated();
+    }
+
+    @Test
+    public void testOnRecentTaskListFrozenChanged() {
+        mImpl.onRecentTaskListFrozenChanged(true);
+        verify(mCallback).onRecentTaskListFrozenChanged(eq(true));
+        verify(mOtherCallback).onRecentTaskListFrozenChanged(eq(true));
+    }
+
+    @Test
+    public void testOnTaskStackChanged() {
+        mImpl.onTaskStackChanged();
+        verify(mCallback).onTaskStackChangedBackground();
+        verify(mCallback).onTaskStackChanged();
+        verify(mOtherCallback).onTaskStackChangedBackground();
+        verify(mOtherCallback).onTaskStackChanged();
+    }
+
+    @Test
+    public void testOnTaskProfileLocked() {
+        mImpl.onTaskProfileLocked(1, 2);
+        verify(mCallback).onTaskProfileLocked(eq(1), eq(2));
+        verify(mOtherCallback).onTaskProfileLocked(eq(1), eq(2));
+    }
+
+    @Test
+    public void testOnTaskDisplayChanged() {
+        mImpl.onTaskDisplayChanged(1, 2);
+        verify(mCallback).onTaskDisplayChanged(eq(1), eq(2));
+        verify(mOtherCallback).onTaskDisplayChanged(eq(1), eq(2));
+    }
+
+    @Test
+    public void testOnTaskCreated() {
+        mImpl.onTaskCreated(1, new ComponentName("a", "b"));
+        verify(mCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+        verify(mOtherCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+    }
+
+    @Test
+    public void testOnTaskRemoved() {
+        mImpl.onTaskRemoved(123);
+        verify(mCallback).onTaskRemoved(eq(123));
+        verify(mOtherCallback).onTaskRemoved(eq(123));
+    }
+
+    @Test
+    public void testOnTaskMovedToFront() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onTaskMovedToFront(info);
+        verify(mCallback).onTaskMovedToFront(eq(info));
+        verify(mOtherCallback).onTaskMovedToFront(eq(info));
+    }
+
+    @Test
+    public void testOnTaskDescriptionChanged() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onTaskDescriptionChanged(info);
+        verify(mCallback).onTaskDescriptionChanged(eq(info));
+        verify(mOtherCallback).onTaskDescriptionChanged(eq(info));
+    }
+
+    @Test
+    public void testOnTaskSnapshotChanged() {
+        ActivityManager.TaskSnapshot snapshot = mock(ActivityManager.TaskSnapshot.class);
+        mImpl.onTaskSnapshotChanged(123, snapshot);
+        verify(mCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+        verify(mOtherCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+    }
+
+    @Test
+    public void testOnBackPressedOnTaskRoot() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onBackPressedOnTaskRoot(info);
+        verify(mCallback).onBackPressedOnTaskRoot(eq(info));
+        verify(mOtherCallback).onBackPressedOnTaskRoot(eq(info));
+    }
+
+    @Test
+    public void testOnActivityRestartAttempt() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onActivityRestartAttempt(info, true, true, true);
+        verify(mCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+        verify(mOtherCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+    }
+
+    @Test
+    public void testOnActivityPinned() {
+        mImpl.onActivityPinned("abc", 1, 2, 3);
+        verify(mCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+        verify(mOtherCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+    }
+
+    @Test
+    public void testOnActivityUnpinned() {
+        mImpl.onActivityUnpinned();
+        verify(mCallback).onActivityUnpinned();
+        verify(mOtherCallback).onActivityUnpinned();
+    }
+
+    @Test
+    public void testOnActivityForcedResizable() {
+        mImpl.onActivityForcedResizable("abc", 1, 2);
+        verify(mCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+        verify(mOtherCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+    }
+
+    @Test
+    public void testOnActivityDismissingDockedStack() {
+        mImpl.onActivityDismissingDockedStack();
+        verify(mCallback).onActivityDismissingDockedStack();
+        verify(mOtherCallback).onActivityDismissingDockedStack();
+    }
+
+    @Test
+    public void testOnActivityLaunchOnSecondaryDisplayFailed() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onActivityLaunchOnSecondaryDisplayFailed(info, 1);
+        verify(mCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+        verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+    }
+
+    @Test
+    public void testOnActivityLaunchOnSecondaryDisplayRerouted() {
+        ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+        mImpl.onActivityLaunchOnSecondaryDisplayRerouted(info, 1);
+        verify(mCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+        verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+    }
+
+    @Test
+    public void testOnActivityRequestedOrientationChanged() {
+        mImpl.onActivityRequestedOrientationChanged(1, 2);
+        verify(mCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+        verify(mOtherCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+    }
+
+    @Test
+    public void testOnActivityRotation() {
+        mImpl.onActivityRotation(123);
+        verify(mCallback).onActivityRotation(eq(123));
+        verify(mOtherCallback).onActivityRotation(eq(123));
+    }
+
+    @Test
+    public void testOnSizeCompatModeActivityChanged() {
+        IBinder b = mock(IBinder.class);
+        mImpl.onSizeCompatModeActivityChanged(123, b);
+        verify(mCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+        verify(mOtherCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+    }
+
+    /**
+     * Handler that synchronously calls TaskStackListenerImpl#handleMessage() when it receives a
+     * message.
+     */
+    private class ProxyToListenerImplHandler extends Handler {
+        public ProxyToListenerImplHandler(Callback callback) {
+            super(callback);
+        }
+
+        @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            return mImpl.handleMessage(msg);
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index affd736..fad1f05 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -35,6 +35,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -68,10 +69,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.function.Consumer;
 
 /**
  * Tests for the drag and drop policy.
@@ -124,6 +128,12 @@
         doReturn(new Rect(50, 0, 100, 100)).when(divider)
                 .getNonMinimizedSplitScreenSecondaryBounds();
 
+        doAnswer((Answer<Void>) invocation -> {
+            Consumer<Boolean> callback = invocation.getArgument(0);
+            callback.accept(true);
+            return null;
+        }).when(mSplitScreen).registerInSplitScreenListener(any());
+
         mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
         mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
         mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 3645f1e..8ef077e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -33,6 +33,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -64,6 +65,8 @@
     OneHandedTimeoutHandler mMockTimeoutHandler;
     @Mock
     IOverlayManager mMockOverlayManager;
+    @Mock
+    TaskStackListenerImpl mMockTaskStackListener;
 
     @Before
     public void setUp() throws Exception {
@@ -76,7 +79,8 @@
                 mMockTouchHandler,
                 mMockTutorialHandler,
                 mMockGestureHandler,
-                mMockOverlayManager);
+                mMockOverlayManager,
+                mMockTaskStackListener);
         mOneHandedController = Mockito.spy(oneHandedController);
         mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 3341c9c..ba8c737 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -25,6 +25,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -47,6 +48,8 @@
     OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
     @Mock
     IOverlayManager mMockOverlayManager;
+    @Mock
+    TaskStackListenerImpl mMockTaskStackListener;
 
     @Before
     public void setUp() {
@@ -60,7 +63,8 @@
                 mTouchHandler,
                 mTutorialHandler,
                 mGestureHandler,
-                mMockOverlayManager);
+                mMockOverlayManager,
+                mMockTaskStackListener);
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
index a3eaac4..ba60d3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
@@ -17,7 +17,6 @@
 package com.android.wm.shell.pip;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
@@ -51,8 +50,6 @@
     private static final float DEFAULT_ASPECT_RATIO = 1f;
     private static final float MIN_ASPECT_RATIO = 0.5f;
     private static final float MAX_ASPECT_RATIO = 2f;
-    private static final Rect EMPTY_CURRENT_BOUNDS = null;
-    private static final Size EMPTY_MINIMAL_SIZE = null;
 
     private PipBoundsHandler mPipBoundsHandler;
     private DisplayInfo mDefaultDisplayInfo;
@@ -115,7 +112,7 @@
     }
 
     @Test
-    public void getDestinationBounds_returnBoundsMatchesAspectRatio() {
+    public void getEntryDestinationBounds_returnBoundsMatchesAspectRatio() {
         final float[] aspectRatios = new float[] {
                 (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2,
                 DEFAULT_ASPECT_RATIO,
@@ -123,8 +120,7 @@
         };
         for (float aspectRatio : aspectRatios) {
             mPipBoundsState.setAspectRatio(aspectRatio);
-            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+            final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
             final float actualAspectRatio =
                     destinationBounds.width() / (destinationBounds.height() * 1f);
             assertEquals("Destination bounds matches the given aspect ratio",
@@ -133,15 +129,14 @@
     }
 
     @Test
-    public void getDestinationBounds_invalidAspectRatio_returnsDefaultAspectRatio() {
+    public void getEntryDestinationBounds_invalidAspectRatio_returnsDefaultAspectRatio() {
         final float[] invalidAspectRatios = new float[] {
                 MIN_ASPECT_RATIO / 2,
                 MAX_ASPECT_RATIO * 2
         };
         for (float aspectRatio : invalidAspectRatios) {
             mPipBoundsState.setAspectRatio(aspectRatio);
-            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+            final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
             final float actualAspectRatio =
                     destinationBounds.width() / (destinationBounds.height() * 1f);
             assertEquals("Destination bounds fallbacks to default aspect ratio",
@@ -151,14 +146,14 @@
     }
 
     @Test
-    public void  getDestinationBounds_withCurrentBounds_returnBoundsMatchesAspectRatio() {
+    public void  getAdjustedDestinationBounds_returnBoundsMatchesAspectRatio() {
         final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
         final Rect currentBounds = new Rect(0, 0, 0, 100);
         currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
 
         mPipBoundsState.setAspectRatio(aspectRatio);
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(currentBounds,
-                EMPTY_MINIMAL_SIZE);
+        final Rect destinationBounds = mPipBoundsHandler.getAdjustedDestinationBounds(
+                currentBounds, aspectRatio);
 
         final float actualAspectRatio =
                 destinationBounds.width() / (destinationBounds.height() * 1f);
@@ -167,7 +162,7 @@
     }
 
     @Test
-    public void getDestinationBounds_withMinSize_returnMinBounds() {
+    public void getEntryDestinationBounds_withMinSize_returnMinBounds() {
         final float[] aspectRatios = new float[] {
                 (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2,
                 DEFAULT_ASPECT_RATIO,
@@ -182,8 +177,8 @@
             final float aspectRatio = aspectRatios[i];
             final Size minimalSize = minimalSizes[i];
             mPipBoundsState.setAspectRatio(aspectRatio);
-            final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                    EMPTY_CURRENT_BOUNDS, minimalSize);
+            mPipBoundsState.setOverrideMinSize(minimalSize);
+            final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
             assertTrue("Destination bounds is no smaller than minimal requirement",
                     (destinationBounds.width() == minimalSize.getWidth()
                             && destinationBounds.height() >= minimalSize.getHeight())
@@ -197,15 +192,16 @@
     }
 
     @Test
-    public void getDestinationBounds_withCurrentBounds_ignoreMinBounds() {
+    public void getAdjustedDestinationBounds_ignoreMinBounds() {
         final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
         final Rect currentBounds = new Rect(0, 0, 0, 100);
         currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
         final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2);
 
         mPipBoundsState.setAspectRatio(aspectRatio);
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                currentBounds, minSize);
+        mPipBoundsState.setOverrideMinSize(minSize);
+        final Rect destinationBounds = mPipBoundsHandler.getAdjustedDestinationBounds(
+                currentBounds, aspectRatio);
 
         assertTrue("Destination bounds ignores minimal size",
                 destinationBounds.width() > minSize.getWidth()
@@ -213,33 +209,29 @@
     }
 
     @Test
-    public void getDestinationBounds_reentryStateExists_restoreLastSize() {
+    public void getEntryDestinationBounds_reentryStateExists_restoreLastSize() {
         mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
-        final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect reentryBounds = mPipBoundsHandler.getEntryDestinationBounds();
         reentryBounds.scale(1.25f);
         final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds);
 
         mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction);
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
 
         assertEquals(reentryBounds.width(), destinationBounds.width());
         assertEquals(reentryBounds.height(), destinationBounds.height());
     }
 
     @Test
-    public void getDestinationBounds_reentryStateExists_restoreLastPosition() {
+    public void getEntryDestinationBounds_reentryStateExists_restoreLastPosition() {
         mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
-        final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect reentryBounds = mPipBoundsHandler.getEntryDestinationBounds();
         reentryBounds.offset(0, -100);
         final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds);
 
         mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction);
 
-        final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect destinationBounds = mPipBoundsHandler.getEntryDestinationBounds();
 
         assertBoundsInclusionWithMargin("restoreLastPosition", reentryBounds, destinationBounds);
     }
@@ -248,12 +240,10 @@
     public void setShelfHeight_offsetBounds() {
         final int shelfHeight = 100;
         mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
-        final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect oldPosition = mPipBoundsHandler.getEntryDestinationBounds();
 
-        mPipBoundsHandler.setShelfHeight(true, shelfHeight);
-        final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        mPipBoundsState.setShelfVisibility(true, shelfHeight);
+        final Rect newPosition = mPipBoundsHandler.getEntryDestinationBounds();
 
         oldPosition.offset(0, -shelfHeight);
         assertBoundsInclusionWithMargin("offsetBounds by shelf", oldPosition, newPosition);
@@ -263,27 +253,23 @@
     public void onImeVisibilityChanged_offsetBounds() {
         final int imeHeight = 100;
         mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
-        final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect oldPosition = mPipBoundsHandler.getEntryDestinationBounds();
 
-        mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight);
-        final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        mPipBoundsState.setImeVisibility(true, imeHeight);
+        final Rect newPosition = mPipBoundsHandler.getEntryDestinationBounds();
 
         oldPosition.offset(0, -imeHeight);
         assertBoundsInclusionWithMargin("offsetBounds by IME", oldPosition, newPosition);
     }
 
     @Test
-    public void getDestinationBounds_noReentryState_useDefaultBounds() {
+    public void getEntryDestinationBounds_noReentryState_useDefaultBounds() {
         mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
-        final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect defaultBounds = mPipBoundsHandler.getEntryDestinationBounds();
 
         mPipBoundsState.clearReentryState();
 
-        final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(
-                EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+        final Rect actualBounds = mPipBoundsHandler.getEntryDestinationBounds();
 
         assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds);
     }
@@ -296,13 +282,4 @@
                 + " with error margin " + ROUNDING_ERROR_MARGIN,
                 expectedWithMargin.contains(actual));
     }
-
-    private void assertNonBoundsInclusionWithMargin(String from, Rect expected, Rect actual) {
-        final Rect expectedWithMargin = new Rect(expected);
-        expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN);
-        assertFalse(from + ": expect " + expected
-                        + " not contains " + actual
-                        + " with error margin " + ROUNDING_ERROR_MARGIN,
-                expectedWithMargin.contains(actual));
-    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index 5e11de7..59e10c1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -19,6 +19,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 
 import android.content.ComponentName;
 import android.graphics.Rect;
@@ -34,6 +37,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.function.BiConsumer;
+
 /**
  * Tests for {@link PipBoundsState}.
  */
@@ -109,4 +114,25 @@
 
         assertNull(mPipBoundsState.getReentryState());
     }
+
+    @Test
+    public void testSetShelfVisibility_changed_callbackInvoked() {
+        final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+        mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+        mPipBoundsState.setShelfVisibility(true, 100);
+
+        verify(callback).accept(true, 100);
+    }
+
+    @Test
+    public void testSetShelfVisibility_notChanged_callbackNotInvoked() {
+        final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+        mPipBoundsState.setShelfVisibility(true, 100);
+        mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+        mPipBoundsState.setShelfVisibility(true, 100);
+
+        verify(callback, never()).accept(true, 100);
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index f4143f6..08841bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -18,7 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.doNothing;
@@ -30,12 +30,14 @@
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
 import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Rational;
+import android.util.Size;
 import android.view.DisplayInfo;
 import android.window.WindowContainerToken;
 
@@ -114,6 +116,15 @@
     }
 
     @Test
+    public void startSwipePipToHome_updatesOverrideMinSize() {
+        final Size minSize = new Size(100, 80);
+
+        mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize), null);
+
+        assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+    }
+
+    @Test
     public void onTaskAppeared_updatesAspectRatio() {
         final Rational aspectRatio = new Rational(2, 1);
 
@@ -132,6 +143,17 @@
     }
 
     @Test
+    public void onTaskAppeared_updatesOverrideMinSize() {
+        final Size minSize = new Size(100, 80);
+
+        mSpiedPipTaskOrganizer.onTaskAppeared(
+                createTaskInfo(mComponent1, createPipParams(null), minSize),
+                null /* leash */);
+
+        assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+    }
+
+    @Test
     public void onTaskInfoChanged_updatesAspectRatioIfChanged() {
         final Rational startAspectRatio = new Rational(2, 1);
         final Rational newAspectRatio = new Rational(1, 2);
@@ -155,11 +177,23 @@
         assertEquals(mComponent2, mPipBoundsState.getLastPipComponentName());
     }
 
+    @Test
+    public void onTaskInfoChanged_updatesOverrideMinSize() {
+        mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
+                createPipParams(null)), null /* leash */);
+
+        final Size minSize = new Size(100, 80);
+        mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
+                createPipParams(null), minSize));
+
+        assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+    }
+
     private void preparePipTaskOrg() {
         final DisplayInfo info = new DisplayInfo();
         mPipBoundsState.setDisplayInfo(info);
-        when(mMockPipBoundsHandler.getDestinationBounds(any(), any())).thenReturn(new Rect());
-        when(mMockPipBoundsHandler.getDestinationBounds(any(), any(), anyBoolean()))
+        when(mMockPipBoundsHandler.getEntryDestinationBounds()).thenReturn(new Rect());
+        when(mMockPipBoundsHandler.getAdjustedDestinationBounds(any(), anyFloat()))
                 .thenReturn(new Rect());
         mPipBoundsState.setDisplayInfo(info);
         mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
@@ -169,13 +203,28 @@
 
     private static ActivityManager.RunningTaskInfo createTaskInfo(
             ComponentName componentName, PictureInPictureParams params) {
+        return createTaskInfo(componentName, params, null /* minSize */);
+    }
+
+    private static ActivityManager.RunningTaskInfo createTaskInfo(
+            ComponentName componentName, PictureInPictureParams params, Size minSize) {
         final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
         info.token = mock(WindowContainerToken.class);
         info.pictureInPictureParams = params;
         info.topActivity = componentName;
+        if (minSize != null) {
+            info.topActivityInfo = createActivityInfo(minSize);
+        }
         return info;
     }
 
+    private static ActivityInfo createActivityInfo(Size minSize) {
+        final ActivityInfo activityInfo = new ActivityInfo();
+        activityInfo.windowLayout = new ActivityInfo.WindowLayout(
+                0, 0, 0, 0, 0, minSize.getWidth(), minSize.getHeight());
+        return activityInfo;
+    }
+
     private static PictureInPictureParams createPipParams(Rational aspectRatio) {
         return new PictureInPictureParams.Builder()
                 .setAspectRatio(aspectRatio)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index a00a3b6..745d188 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -39,6 +39,7 @@
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.PipBoundsHandler;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipMediaController;
@@ -68,6 +69,7 @@
     @Mock private PipTouchHandler mMockPipTouchHandler;
     @Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
     @Mock private PipBoundsState mMockPipBoundsState;
+    @Mock private TaskStackListenerImpl mMockTaskStackListener;
     @Mock private ShellExecutor mMockExecutor;
 
     @Before
@@ -76,7 +78,8 @@
         mPipController = new PipController(mContext, mMockDisplayController,
                 mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
                 mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
-                mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor);
+                mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+                mMockExecutor);
         doAnswer(invocation -> {
             ((Runnable) invocation.getArgument(0)).run();
             return null;
@@ -108,7 +111,8 @@
         assertNull(PipController.create(spyContext, mMockDisplayController,
                 mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
                 mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
-                mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor));
+                mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+                mMockExecutor));
     }
 
     @Test
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index b2c39c9..ccce403 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -183,7 +183,6 @@
         ALOGI("%s", ss.str().c_str());
         // Just so we have something that counts up, the value is largely irrelevant
         ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
-        android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration));
     }
 }
 
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index c8a21f6..895c6d0 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -38,6 +38,8 @@
     DrawColor,
     DrawRect,
     DrawRoundRect,
+    DrawRoundRectProperty,
+    DrawCircleProperty,
     DrawCircle,
     DrawOval,
     DrawArc,
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 27eca21..afd88c0 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -20,6 +20,7 @@
 #include <SkCanvas.h>
 #include <SkPath.h>
 #include <log/log.h>
+#include "CanvasProperty.h"
 
 #include "CanvasOpTypes.h"
 
@@ -103,6 +104,36 @@
 //   Drawing Ops
 //  ---------------------------------------------
 
+template<>
+struct CanvasOp<CanvasOpType::DrawRoundRectProperty> {
+    sp<uirenderer::CanvasPropertyPrimitive> left;
+    sp<uirenderer::CanvasPropertyPrimitive> top;
+    sp<uirenderer::CanvasPropertyPrimitive> right;
+    sp<uirenderer::CanvasPropertyPrimitive> bottom;
+    sp<uirenderer::CanvasPropertyPrimitive> rx;
+    sp<uirenderer::CanvasPropertyPrimitive> ry;
+    sp<uirenderer::CanvasPropertyPaint> paint;
+
+    void draw(SkCanvas* canvas) const {
+        SkRect rect = SkRect::MakeLTRB(left->value, top->value, right->value, bottom->value);
+        canvas->drawRoundRect(rect, rx->value, ry->value, paint->value);
+    }
+    ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawCircleProperty> {
+    sp<uirenderer::CanvasPropertyPrimitive> x;
+    sp<uirenderer::CanvasPropertyPrimitive> y;
+    sp<uirenderer::CanvasPropertyPrimitive> radius;
+    sp<uirenderer::CanvasPropertyPaint> paint;
+
+    void draw(SkCanvas* canvas) const {
+        canvas->drawCircle(x->value, y->value, radius->value, paint->value);
+    }
+    ASSERT_DRAWABLE()
+};
+
 template <>
 struct CanvasOp<CanvasOpType::DrawColor> {
     SkColor4f color;
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index ef8d8f4..0c3ef01 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -41,6 +41,9 @@
     enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
     Style fAPIStyle;
 
+    // base weight in CSS-style units, 1..1000
+    int fBaseWeight;
+
     static const Typeface* resolveDefault(const Typeface* src);
 
     // The following three functions create new Typeface from an existing Typeface with a different
@@ -81,10 +84,6 @@
 
     // Sets roboto font as the default typeface for testing purpose.
     static void setRobotoTypefaceForTest();
-
-private:
-    // base weight in CSS-style units, 1..1000
-    int fBaseWeight;
 };
 }
 
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 7d2583a..52522a3 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -67,6 +67,8 @@
             return "image/webp";
         case SkEncodedImageFormat::kHEIF:
             return "image/heif";
+        case SkEncodedImageFormat::kAVIF:
+            return "image/avif";
         case SkEncodedImageFormat::kWBMP:
             return "image/vnd.wap.wbmp";
         case SkEncodedImageFormat::kDNG:
diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index 2a5f402..dc066da 100644
--- a/libs/hwui/jni/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -16,10 +16,13 @@
 
 #include "FontUtils.h"
 #include "GraphicsJNI.h"
+#include "fonts/Font.h"
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
+#include "SkData.h"
 #include "SkTypeface.h"
 #include <hwui/Typeface.h>
+#include <minikin/FontCollection.h>
 #include <minikin/FontFamily.h>
 #include <minikin/SystemFonts.h>
 
@@ -132,6 +135,88 @@
                                            toTypeface(ptr)->fFontCollection);
 }
 
+static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSkia(
+        minikin::BufferReader* reader) {
+    std::string_view fontPath = reader->readString();
+    int fontIndex = reader->read<int>();
+    const minikin::FontVariation* axesPtr;
+    uint32_t axesCount;
+    std::tie(axesPtr, axesCount) = reader->readArray<minikin::FontVariation>();
+    return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr<minikin::MinikinFont> {
+        std::string path(fontPath.data(), fontPath.size());
+        sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
+        const void* fontPtr = data->data();
+        size_t fontSize = data->size();
+        std::vector<minikin::FontVariation> axes(axesPtr, axesPtr + axesCount);
+        std::shared_ptr<minikin::MinikinFont> minikinFont =
+                fonts::createMinikinFontSkia(std::move(data), fontPath, fontPtr, fontSize,
+                                             fontIndex, axes);
+        if (minikinFont == nullptr) {
+            ALOGE("Failed to create MinikinFontSkia: %s", path.c_str());
+            return nullptr;
+        }
+        return minikinFont;
+    };
+}
+
+static void writeMinikinFontSkia(minikin::BufferWriter* writer,
+        const minikin::MinikinFont* typeface) {
+    writer->writeString(typeface->GetFontPath());
+    writer->write<int>(typeface->GetFontIndex());
+    const std::vector<minikin::FontVariation>& axes = typeface->GetAxes();
+    writer->writeArray<minikin::FontVariation>(axes.data(), axes.size());
+}
+
+static jint Typeface_writeTypefaces(JNIEnv *env, jobject, jobject buffer, jlongArray faceHandles) {
+    ScopedLongArrayRO faces(env, faceHandles);
+    std::vector<Typeface*> typefaces;
+    typefaces.reserve(faces.size());
+    for (size_t i = 0; i < faces.size(); i++) {
+        typefaces.push_back(toTypeface(faces[i]));
+    }
+    void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+    minikin::BufferWriter writer(addr);
+    std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections;
+    std::unordered_map<std::shared_ptr<minikin::FontCollection>, size_t> fcToIndex;
+    for (Typeface* typeface : typefaces) {
+        bool inserted = fcToIndex.emplace(typeface->fFontCollection, fontCollections.size()).second;
+        if (inserted) {
+            fontCollections.push_back(typeface->fFontCollection);
+        }
+    }
+    minikin::FontCollection::writeVector<writeMinikinFontSkia>(&writer, fontCollections);
+    writer.write<uint32_t>(typefaces.size());
+    for (Typeface* typeface : typefaces) {
+      writer.write<uint32_t>(fcToIndex.find(typeface->fFontCollection)->second);
+      typeface->fStyle.writeTo(&writer);
+      writer.write<Typeface::Style>(typeface->fAPIStyle);
+      writer.write<int>(typeface->fBaseWeight);
+    }
+    return static_cast<jint>(writer.size());
+}
+
+static jlongArray Typeface_readTypefaces(JNIEnv *env, jobject, jobject buffer) {
+    void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+    if (addr == nullptr) return nullptr;
+    minikin::BufferReader reader(addr);
+    std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections =
+            minikin::FontCollection::readVector<readMinikinFontSkia>(&reader);
+    uint32_t typefaceCount = reader.read<uint32_t>();
+    std::vector<jlong> faceHandles;
+    faceHandles.reserve(typefaceCount);
+    for (uint32_t i = 0; i < typefaceCount; i++) {
+        Typeface* typeface = new Typeface;
+        typeface->fFontCollection = fontCollections[reader.read<uint32_t>()];
+        typeface->fStyle = minikin::FontStyle(&reader);
+        typeface->fAPIStyle = reader.read<Typeface::Style>();
+        typeface->fBaseWeight = reader.read<int>();
+        faceHandles.push_back(toJLong(typeface));
+    }
+    const jlongArray result = env->NewLongArray(typefaceCount);
+    env->SetLongArrayRegion(result, 0, typefaceCount, faceHandles.data());
+    return result;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gTypefaceMethods[] = {
@@ -150,6 +235,8 @@
     { "nativeGetSupportedAxes",   "(J)[I",  (void*)Typeface_getSupportedAxes },
     { "nativeRegisterGenericFamily", "(Ljava/lang/String;J)V",
           (void*)Typeface_registerGenericFamily },
+    { "nativeWriteTypefaces", "(Ljava/nio/ByteBuffer;[J)I", (void*)Typeface_writeTypefaces},
+    { "nativeReadTypefaces", "(Ljava/nio/ByteBuffer;)[J", (void*)Typeface_readTypefaces},
 };
 
 int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 21fcd2f..f0c7793 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "Minikin"
 
+#include "Font.h"
 #include "SkData.h"
 #include "SkFont.h"
 #include "SkFontMetrics.h"
@@ -95,29 +96,14 @@
     jobject fontRef = MakeGlobalRefOrDie(env, buffer);
     sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
             release_global_ref, reinterpret_cast<void*>(fontRef)));
-
-    FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
-    for (const auto& axis : builder->axes) {
-        skVariation.push_back({axis.axisTag, axis.value});
-    }
-
-    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
-    SkFontArguments args;
-    args.setCollectionIndex(ttcIndex);
-    args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
-
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
-    if (face == nullptr) {
+    std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
+        std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
+        fontPtr, fontSize, ttcIndex, builder->axes);
+    if (minikinFont == nullptr) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                           "Failed to create internal object. maybe invalid font data.");
         return 0;
     }
-    std::shared_ptr<minikin::MinikinFont> minikinFont =
-            std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
-                                              std::string_view(fontPath.c_str(), fontPath.size()),
-                                              ttcIndex, builder->axes);
     std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
                     .setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
     return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
@@ -312,4 +298,31 @@
             gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods));
 }
 
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+        sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+        int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
+    FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
+    for (const auto& axis : axes) {
+        skVariation.push_back({axis.axisTag, axis.value});
+    }
+
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
+
+    SkFontArguments args;
+    args.setCollectionIndex(ttcIndex);
+    args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
+
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
+    if (face == nullptr) {
+        return nullptr;
+    }
+    return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
+                                             fontPath, ttcIndex, axes);
 }
+
+}  // namespace fonts
+
+}  // namespace android
diff --git a/libs/hwui/jni/fonts/Font.h b/libs/hwui/jni/fonts/Font.h
new file mode 100644
index 0000000..b5d20bf
--- /dev/null
+++ b/libs/hwui/jni/fonts/Font.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+#ifndef FONTS_FONT_H_
+#define FONTS_FONT_H_
+
+#include <minikin/FontVariation.h>
+#include <minikin/MinikinFont.h>
+#include <SkRefCnt.h>
+
+#include <string_view>
+#include <vector>
+
+class SkData;
+
+namespace android {
+
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+        sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+        int ttcIndex, const std::vector<minikin::FontVariation>& axes);
+
+} // namespace fonts
+
+} // namespace android
+
+#endif /* FONTS_FONT_H_ */
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index c90d1a4..2311924 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -22,6 +22,9 @@
 
 #include <tests/common/CallCountingCanvas.h>
 
+#include "SkColor.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::test;
@@ -178,6 +181,21 @@
     EXPECT_EQ(buffer.size(), 0);
 }
 
+TEST(CanvasOp, simpleDrawPaint) {
+    CanvasOpBuffer buffer;
+    EXPECT_EQ(buffer.size(), 0);
+    buffer.push(CanvasOp<Op::DrawColor> {
+        .color = SkColor4f{1, 1, 1, 1},
+        .mode = SkBlendMode::kSrcIn
+    });
+
+    CallCountingCanvas canvas;
+    EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+    rasterizeCanvasBuffer(buffer, &canvas);
+    EXPECT_EQ(1, canvas.drawPaintCount);
+    EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
 TEST(CanvasOp, simpleDrawRect) {
     CanvasOpBuffer buffer;
     EXPECT_EQ(buffer.size(), 0);
@@ -260,6 +278,60 @@
     EXPECT_EQ(1, canvas.sumTotalDrawCalls());
 }
 
+TEST(CanvasOp, simpleDrawRoundRectProperty) {
+    CanvasOpBuffer buffer;
+    EXPECT_EQ(buffer.size(), 0);
+
+    auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
+    auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
+    auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3));
+    auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4));
+    auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
+    auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6));
+    auto propertyPaint =
+            sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
+
+    buffer.push(CanvasOp<Op::DrawRoundRectProperty> {
+        .left = left,
+        .top = top,
+        .right = right,
+        .bottom = bottom,
+        .rx = radiusX,
+        .ry = radiusY,
+        .paint = propertyPaint
+    });
+
+    CallCountingCanvas canvas;
+    EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+    rasterizeCanvasBuffer(buffer, &canvas);
+    EXPECT_EQ(1, canvas.drawRRectCount);
+    EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawCircleProperty) {
+    CanvasOpBuffer buffer;
+    EXPECT_EQ(buffer.size(), 0);
+
+    auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
+    auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
+    auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
+    auto propertyPaint =
+            sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
+
+    buffer.push(CanvasOp<Op::DrawCircleProperty> {
+        .x = x,
+        .y = y,
+        .radius = radius,
+        .paint = propertyPaint
+    });
+
+    CallCountingCanvas canvas;
+    EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+    rasterizeCanvasBuffer(buffer, &canvas);
+    EXPECT_EQ(1, canvas.drawOvalCount);
+    EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
 TEST(CanvasOp, immediateRendering) {
     auto canvas = std::make_shared<CallCountingCanvas>();
 
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index 5734bf2..bbb5bb8 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -29,10 +29,10 @@
     public static final long LOW_POWER_MODE                                     = 1L << 0;
 
     /**
-     * Bit mask indicating GNSS chipset supports blacklisting satellites.
+     * Bit mask indicating GNSS chipset supports blocklisting satellites.
      * @hide
      */
-    public static final long SATELLITE_BLACKLIST                                = 1L << 1;
+    public static final long SATELLITE_BLOCKLIST                                = 1L << 1;
 
     /**
      * Bit mask indicating GNSS chipset supports geofencing.
@@ -110,14 +110,27 @@
     }
 
     /**
-     * Returns {@code true} if GNSS chipset supports blacklisting satellites, {@code false}
+     * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
+     * otherwise.
+     *
+     * @hide
+     * @deprecated use {@link #hasSatelliteBlocklist} instead.
+     */
+    @SystemApi
+    @Deprecated
+    public boolean hasSatelliteBlacklist() {
+        return hasCapability(SATELLITE_BLOCKLIST);
+    }
+
+    /**
+     * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
      * otherwise.
      *
      * @hide
      */
     @SystemApi
-    public boolean hasSatelliteBlacklist() {
-        return hasCapability(SATELLITE_BLACKLIST);
+    public boolean hasSatelliteBlocklist() {
+        return hasCapability(SATELLITE_BLOCKLIST);
     }
 
     /**
diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl
index 29b483a..ce92661 100644
--- a/location/java/android/location/ILocationListener.aidl
+++ b/location/java/android/location/ILocationListener.aidl
@@ -16,7 +16,7 @@
 
 package android.location;
 
-import android.location.Location;
+import android.location.LocationResult;
 import android.os.IRemoteCallback;
 
 /**
@@ -24,6 +24,7 @@
  */
 oneway interface ILocationListener
 {
-    void onLocationChanged(in Location location, in @nullable IRemoteCallback onCompleteCallback);
+    void onLocationChanged(in LocationResult locationResult, in @nullable IRemoteCallback onCompleteCallback);
     void onProviderEnabledChanged(String provider, boolean enabled);
+    void onFlushComplete(int requestCode);
 }
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 3905e0b..d3dc3b3 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -23,7 +23,6 @@
 import android.location.Geofence;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
 import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
@@ -53,10 +52,13 @@
     void unregisterLocationListener(in ILocationListener listener);
 
     void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, String attributionTag);
-    void unregisterLocationPendingIntent(in PendingIntent intent);
+    void unregisterLocationPendingIntent(in PendingIntent pendingIntent);
 
     void injectLocation(in Location location);
 
+    void requestListenerFlush(String provider, in ILocationListener listener, int requestCode);
+    void requestPendingIntentFlush(String provider, in PendingIntent pendingIntent, int requestCode);
+
     void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
     void removeGeofence(in PendingIntent intent);
 
@@ -86,9 +88,7 @@
     void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
 
     int getGnssBatchSize();
-    void setGnssBatchingCallback(in IBatchedLocationCallback callback, String packageName, String attributionTag);
-    void removeGnssBatchingCallback();
-    void startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName, String attributionTag);
+    void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
     void flushGnssBatch();
     void stopGnssBatch();
 
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 20175d7..b4392b1 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -18,6 +18,7 @@
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
@@ -29,20 +30,22 @@
 import android.util.TimeUtils;
 
 import java.text.DecimalFormat;
+import java.util.Locale;
+import java.util.Objects;
 import java.util.StringTokenizer;
 
 /**
  * A data class representing a geographic location.
  *
- * <p>A location can consist of a latitude, longitude, timestamp,
- * and other information such as bearing, altitude and velocity.
+ * <p>A location may consist of a latitude, longitude, timestamp, and other information such as
+ * bearing, altitude and velocity.
  *
- * <p>All locations generated by the {@link LocationManager} are
- * guaranteed to have a valid latitude, longitude, and timestamp
- * (both UTC time and elapsed real-time since boot), all other
+ * <p>All locations generated through {@link LocationManager} are guaranteed to have a valid
+ * latitude, longitude, and timestamp (both UTC time and elapsed real-time since boot). All other
  * parameters are optional.
  */
 public class Location implements Parcelable {
+
     /**
      * Constant used to specify formatting of a latitude or longitude
      * in the form "[+-]DDD.DDDDD where D indicates degrees.
@@ -78,58 +81,26 @@
     @Deprecated
     public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
 
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mAltitude.
-     */
-    private static final int HAS_ALTITUDE_MASK = 1;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mSpeed.
-     */
-    private static final int HAS_SPEED_MASK = 2;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mBearing.
-     */
-    private static final int HAS_BEARING_MASK = 4;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mHorizontalAccuracy.
-     */
-    private static final int HAS_HORIZONTAL_ACCURACY_MASK = 8;
-    /**
-     * Bit mask for mFieldsMask indicating location is from a mock provider.
-     */
-    private static final int HAS_MOCK_PROVIDER_MASK = 16;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mVerticalAccuracy.
-     */
-    private static final int HAS_VERTICAL_ACCURACY_MASK = 32;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mSpeedAccuracy.
-     */
-    private static final int HAS_SPEED_ACCURACY_MASK = 64;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mBearingAccuracy.
-     */
-    private static final int HAS_BEARING_ACCURACY_MASK = 128;
-    /**
-     * Bit mask for mFieldsMask indicating the presence of mElapsedRealtimeUncertaintyNanos.
-     */
-    private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 256;
+    private static final int HAS_ALTITUDE_MASK = 1 << 0;
+    private static final int HAS_SPEED_MASK = 1 << 1;
+    private static final int HAS_BEARING_MASK = 1 << 2;
+    private static final int HAS_HORIZONTAL_ACCURACY_MASK = 1 << 3;
+    private static final int HAS_MOCK_PROVIDER_MASK = 1 << 4;
+    private static final int HAS_VERTICAL_ACCURACY_MASK = 1 << 5;
+    private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6;
+    private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7;
+    private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8;
 
     // Cached data to make bearing/distance computations more efficient for the case
     // where distanceTo and bearingTo are called in sequence.  Assume this typically happens
     // on the same thread for caching purposes.
-    private static ThreadLocal<BearingDistanceCache> sBearingDistanceCache
-            = new ThreadLocal<BearingDistanceCache>() {
-        @Override
-        protected BearingDistanceCache initialValue() {
-            return new BearingDistanceCache();
-        }
-    };
+    private static final ThreadLocal<BearingDistanceCache> sBearingDistanceCache =
+            ThreadLocal.withInitial(BearingDistanceCache::new);
 
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mProvider;
     private long mTime = 0;
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "{@link #getElapsedRealtimeNanos()}")
     private long mElapsedRealtimeNanos = 0;
     // Estimate of the relative precision of the alignment of this SystemClock
     // timestamp, with the reported measurements in nanoseconds (68% confidence).
@@ -227,8 +198,7 @@
      * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
      */
     public static String convert(double coordinate, int outputType) {
-        if (coordinate < -180.0 || coordinate > 180.0 ||
-            Double.isNaN(coordinate)) {
+        if (coordinate < -180.0 || coordinate > 180.0 || Double.isNaN(coordinate)) {
             throw new IllegalArgumentException("coordinate=" + coordinate);
         }
         if ((outputType != FORMAT_DEGREES) &&
@@ -374,10 +344,10 @@
 
         double sigma = 0.0;
         double deltaSigma = 0.0;
-        double cosSqAlpha = 0.0;
-        double cos2SM = 0.0;
-        double cosSigma = 0.0;
-        double sinSigma = 0.0;
+        double cosSqAlpha;
+        double cos2SM;
+        double cosSigma;
+        double sinSigma;
         double cosLambda = 0.0;
         double sinLambda = 0.0;
 
@@ -428,8 +398,7 @@
             }
         }
 
-        float distance = (float) (b * A * (sigma - deltaSigma));
-        results.mDistance = distance;
+        results.mDistance = (float) (b * A * (sigma - deltaSigma));
         float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
             cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
         initialBearing *= 180.0 / Math.PI;
@@ -536,29 +505,26 @@
     }
 
     /**
-     * Return the UTC time of this fix, in milliseconds since January 1, 1970.
+     * Return the UTC time of this location fix, in milliseconds since epoch (January 1, 1970).
      *
-     * <p>Note that the UTC time on a device is not monotonic: it
-     * can jump forwards or backwards unpredictably. So always use
-     * {@link #getElapsedRealtimeNanos} when calculating time deltas.
+     * <p>Note that the UTC time on a device is not monotonic; it can jump forwards or backwards
+     * unpredictably, so this time should not be used to calculate time deltas between locations.
+     * Instead prefer {@link #getElapsedRealtimeNanos} for that purpose.
      *
-     * <p>On the other hand, {@link #getTime} is useful for presenting
-     * a human readable time to the user, or for carefully comparing
-     * location fixes across reboot or across devices.
+     * <p>On the other hand, this method is useful for presenting a human readable time to the user,
+     * or for carefully comparing location fixes across reboot or across devices.
      *
-     * <p>All locations generated by the {@link LocationManager}
-     * are guaranteed to have a valid UTC time, however remember that
-     * the system time may have changed since the location was generated.
+     * <p>All locations generated by the {@link LocationManager} are guaranteed to have a UTC time,
+     * however remember that the system time may have changed since the location was generated.
      *
-     * @return time of fix, in milliseconds since January 1, 1970.
+     * @return UTC time of fix, in milliseconds since January 1, 1970.
      */
     public long getTime() {
         return mTime;
     }
 
     /**
-     * Set the UTC time of this fix, in milliseconds since January 1,
-     * 1970.
+     * Set the UTC time of this fix, in milliseconds since epoch (January 1, 1970).
      *
      * @param time UTC time of this fix, in milliseconds since January 1, 1970
      */
@@ -886,18 +852,15 @@
     /**
      * Get the estimated vertical accuracy of this location, in meters.
      *
-     * <p>We define vertical accuracy at 68% confidence.  Specifically, as 1-side of the
-     * 2-sided range above and below the estimated altitude reported by {@link #getAltitude()},
-     * within which there is a 68% probability of finding the true altitude.
+     * <p>We define vertical accuracy at 68% confidence. Specifically, as 1-side of the 2-sided
+     * range above and below the estimated altitude reported by {@link #getAltitude()}, within which
+     * there is a 68% probability of finding the true altitude.
      *
      * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
      * considered 1 standard deviation.
      *
-     * <p>For example, if {@link #getAltitude()} returns 150, and
-     * {@link #getVerticalAccuracyMeters()} returns 20 then there is a 68% probability
-     * of the true altitude being between 130 and 170 meters.
-     *
-     * <p>If this location does not have a vertical accuracy, then 0.0 is returned.
+     * <p>For example, if {@link #getAltitude()} returns 150m, and this method returns 20m then
+     * there is a 68% probability of the true altitude being between 130m and 170m.
      */
     public float getVerticalAccuracyMeters() {
         return mVerticalAccuracyMeters;
@@ -940,22 +903,19 @@
     /**
      * Get the estimated speed accuracy of this location, in meters per second.
      *
-     * <p>We define speed accuracy at 68% confidence.  Specifically, as 1-side of the
-     * 2-sided range above and below the estimated speed reported by {@link #getSpeed()},
-     * within which there is a 68% probability of finding the true speed.
+     * <p>We define speed accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
+     * above and below the estimated speed reported by {@link #getSpeed()}, within which there is a
+     * 68% probability of finding the true speed.
      *
-     * <p>In the case where the underlying
-     * distribution is assumed Gaussian normal, this would be considered 1 standard deviation.
+     * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
+     * considered 1 standard deviation.
      *
-     * <p>For example, if {@link #getSpeed()} returns 5, and
-     * {@link #getSpeedAccuracyMetersPerSecond()} returns 1, then there is a 68% probability of
-     * the true speed being between 4 and 6 meters per second.
+     * <p>For example, if {@link #getSpeed()} returns 5m/s, and this method returns 1m/s, then there
+     * is a 68% probability of the true speed being between 4m/s and 6m/s.
      *
-     * <p>Note that the speed and speed accuracy is often better than would be obtained simply from
-     * differencing sequential positions, such as when the Doppler measurements from GNSS satellites
-     * are used.
-     *
-     * <p>If this location does not have a speed accuracy, then 0.0 is returned.
+     * <p>Note that the speed and speed accuracy may be more accurate than would be obtained simply
+     * from differencing sequential positions, such as when the Doppler measurements from GNSS
+     * satellites are taken into account.
      */
     public float getSpeedAccuracyMetersPerSecond() {
         return mSpeedAccuracyMetersPerSecond;
@@ -998,18 +958,15 @@
     /**
      * Get the estimated bearing accuracy of this location, in degrees.
      *
-     * <p>We define bearing accuracy at 68% confidence.  Specifically, as 1-side of the
-     * 2-sided range on each side of the estimated bearing reported by {@link #getBearing()},
-     * within which there is a 68% probability of finding the true bearing.
+     * <p>We define bearing accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
+     * on each side of the estimated bearing reported by {@link #getBearing()}, within which there
+     * is a 68% probability of finding the true bearing.
      *
      * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
      * considered 1 standard deviation.
      *
-     * <p>For example, if {@link #getBearing()} returns 60, and
-     * {@link #getBearingAccuracyDegrees()} returns 10, then there is a 68% probability of the
-     * true bearing being between 50 and 70 degrees.
-     *
-     * <p>If this location does not have a bearing accuracy, then 0.0 is returned.
+     * <p>For example, if {@link #getBearing()} returns 60°, and this method returns 10°, then there
+     * is a 68% probability of the true bearing being between 50° and 70°.
      */
     public float getBearingAccuracyDegrees() {
         return mBearingAccuracyDegrees;
@@ -1056,11 +1013,7 @@
      */
     @SystemApi
     public boolean isComplete() {
-        if (mProvider == null) return false;
-        if (!hasAccuracy()) return false;
-        if (mTime == 0) return false;
-        if (mElapsedRealtimeNanos == 0) return false;
-        return true;
+        return mProvider != null && hasAccuracy() && mTime != 0 && mElapsedRealtimeNanos != 0;
     }
 
     /**
@@ -1084,10 +1037,9 @@
     }
 
     /**
-     * Returns additional provider-specific information about the
-     * location fix as a Bundle.  The keys and values are determined
-     * by the provider.  If no additional information is available,
-     * null is returned.
+     * Returns additional provider-specific information about the location fix as a Bundle. The keys
+     * and values are determined by the provider.  If no additional information is available, null
+     * is returned.
      *
      * <p> A number of common key/value pairs are listed
      * below. Providers that use any of the keys on this list must
@@ -1096,53 +1048,105 @@
      * <ul>
      * <li> satellites - the number of satellites used to derive the fix
      * </ul>
+     *
+     * @deprecated Do not use. For GNSS related information, prefer listening for GNSS status
+     *             information via {@link LocationManager}.
      */
+    @Deprecated
     public Bundle getExtras() {
         return mExtras;
     }
 
     /**
-     * Sets the extra information associated with this fix to the
-     * given Bundle.
+     * Sets the extra information associated with this fix to the given Bundle.
      *
      * <p>Note this stores a copy of the given extras, so any changes to extras after calling this
      * method won't be reflected in the location bundle.
+     *
+     * @deprecated Do not use.
      */
+    @Deprecated
     public void setExtras(Bundle extras) {
         mExtras = (extras == null) ? null : new Bundle(extras);
     }
 
     @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Location location = (Location) o;
+        return mTime == location.mTime
+                && mElapsedRealtimeNanos == location.mElapsedRealtimeNanos
+                && hasElapsedRealtimeUncertaintyNanos()
+                == location.hasElapsedRealtimeUncertaintyNanos()
+                && (!hasElapsedRealtimeUncertaintyNanos() || Double.compare(
+                location.mElapsedRealtimeUncertaintyNanos, mElapsedRealtimeUncertaintyNanos) == 0)
+                && Double.compare(location.mLatitude, mLatitude) == 0
+                && Double.compare(location.mLongitude, mLongitude) == 0
+                && hasAltitude() == location.hasAltitude()
+                && (!hasAltitude() || Double.compare(location.mAltitude, mAltitude) == 0)
+                && hasSpeed() == location.hasSpeed()
+                && (!hasSpeed() || Float.compare(location.mSpeed, mSpeed) == 0)
+                && hasBearing() == location.hasBearing()
+                && (!hasBearing() || Float.compare(location.mBearing, mBearing) == 0)
+                && hasAccuracy() == location.hasAccuracy()
+                && (!hasAccuracy() || Float.compare(location.mHorizontalAccuracyMeters,
+                mHorizontalAccuracyMeters) == 0)
+                && hasVerticalAccuracy() == location.hasVerticalAccuracy()
+                && (!hasVerticalAccuracy() || Float.compare(location.mVerticalAccuracyMeters,
+                mVerticalAccuracyMeters) == 0)
+                && hasSpeedAccuracy() == location.hasSpeedAccuracy()
+                && (!hasSpeedAccuracy() || Float.compare(location.mSpeedAccuracyMetersPerSecond,
+                mSpeedAccuracyMetersPerSecond) == 0)
+                && hasBearingAccuracy() == location.hasBearingAccuracy()
+                && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
+                mBearingAccuracyDegrees) == 0)
+                && Objects.equals(mProvider, location.mProvider)
+                && Objects.equals(mExtras, location.mExtras);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mProvider, mElapsedRealtimeNanos, mLatitude, mLongitude);
+    }
+
+    @Override
     public String toString() {
         StringBuilder s = new StringBuilder();
         s.append("Location[");
         s.append(mProvider);
-        s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
-        if (hasAccuracy()) s.append(String.format(" hAcc=%.0f", mHorizontalAccuracyMeters));
-        else s.append(" hAcc=???");
-        if (mTime == 0) {
-            s.append(" t=?!?");
+        s.append(" ").append(String.format(Locale.ROOT, "%.6f,%.6f", mLatitude, mLongitude));
+        if (hasAccuracy()) {
+            s.append(" hAcc=").append(mHorizontalAccuracyMeters);
         }
-        if (mElapsedRealtimeNanos == 0) {
-            s.append(" et=?!?");
-        } else {
-            s.append(" et=");
-            TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
+        s.append(" et=");
+        TimeUtils.formatDuration(getElapsedRealtimeMillis(), s);
+        if (hasAltitude()) {
+            s.append(" alt=").append(mAltitude);
+            if (hasVerticalAccuracy()) {
+                s.append(" vAcc=").append(mVerticalAccuracyMeters);
+            }
         }
-        if (hasElapsedRealtimeUncertaintyNanos()) {
-            s.append(" etAcc=");
-            TimeUtils.formatDuration((long) (mElapsedRealtimeUncertaintyNanos / 1000000), s);
+        if (hasSpeed()) {
+            s.append(" vel=").append(mSpeed);
+            if (hasSpeedAccuracy()) {
+                s.append(" sAcc=").append(mSpeedAccuracyMetersPerSecond);
+            }
         }
-        if (hasAltitude()) s.append(" alt=").append(mAltitude);
-        if (hasSpeed()) s.append(" vel=").append(mSpeed);
-        if (hasBearing()) s.append(" bear=").append(mBearing);
-        if (hasVerticalAccuracy()) s.append(String.format(" vAcc=%.0f", mVerticalAccuracyMeters));
-        else s.append(" vAcc=???");
-        if (hasSpeedAccuracy()) s.append(String.format(" sAcc=%.0f", mSpeedAccuracyMetersPerSecond));
-        else s.append(" sAcc=???");
-        if (hasBearingAccuracy()) s.append(String.format(" bAcc=%.0f", mBearingAccuracyDegrees));
-        else s.append(" bAcc=???");
-        if (isFromMockProvider()) s.append(" mock");
+        if (hasBearing()) {
+            s.append(" bear=").append(mBearing);
+            if (hasBearingAccuracy()) {
+                s.append(" bAcc=").append(mBearingAccuracyDegrees);
+            }
+        }
+        if (isFromMockProvider()) {
+            s.append(" mock");
+        }
 
         if (mExtras != null) {
             s.append(" {").append(mExtras).append('}');
@@ -1155,25 +1159,40 @@
         pw.println(prefix + toString());
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<Location> CREATOR =
+    public static final @NonNull Parcelable.Creator<Location> CREATOR =
         new Parcelable.Creator<Location>() {
         @Override
         public Location createFromParcel(Parcel in) {
-            String provider = in.readString();
-            Location l = new Location(provider);
+            Location l = new Location(in.readString());
+            l.mFieldsMask = in.readInt();
             l.mTime = in.readLong();
             l.mElapsedRealtimeNanos = in.readLong();
-            l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
-            l.mFieldsMask = in.readInt();
+            if (l.hasElapsedRealtimeUncertaintyNanos()) {
+                l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
+            }
             l.mLatitude = in.readDouble();
             l.mLongitude = in.readDouble();
-            l.mAltitude = in.readDouble();
-            l.mSpeed = in.readFloat();
-            l.mBearing = in.readFloat();
-            l.mHorizontalAccuracyMeters = in.readFloat();
-            l.mVerticalAccuracyMeters = in.readFloat();
-            l.mSpeedAccuracyMetersPerSecond = in.readFloat();
-            l.mBearingAccuracyDegrees = in.readFloat();
+            if (l.hasAltitude()) {
+                l.mAltitude = in.readDouble();
+            }
+            if (l.hasSpeed()) {
+                l.mSpeed = in.readFloat();
+            }
+            if (l.hasBearing()) {
+                l.mBearing = in.readFloat();
+            }
+            if (l.hasAccuracy()) {
+                l.mHorizontalAccuracyMeters = in.readFloat();
+            }
+            if (l.hasVerticalAccuracy()) {
+                l.mVerticalAccuracyMeters = in.readFloat();
+            }
+            if (l.hasSpeedAccuracy()) {
+                l.mSpeedAccuracyMetersPerSecond = in.readFloat();
+            }
+            if (l.hasBearingAccuracy()) {
+                l.mBearingAccuracyDegrees = in.readFloat();
+            }
             l.mExtras = Bundle.setDefusable(in.readBundle(), true);
             return l;
         }
@@ -1192,38 +1211,36 @@
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mProvider);
+        parcel.writeInt(mFieldsMask);
         parcel.writeLong(mTime);
         parcel.writeLong(mElapsedRealtimeNanos);
-        parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
-        parcel.writeInt(mFieldsMask);
+        if (hasElapsedRealtimeUncertaintyNanos()) {
+            parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
+        }
         parcel.writeDouble(mLatitude);
         parcel.writeDouble(mLongitude);
-        parcel.writeDouble(mAltitude);
-        parcel.writeFloat(mSpeed);
-        parcel.writeFloat(mBearing);
-        parcel.writeFloat(mHorizontalAccuracyMeters);
-        parcel.writeFloat(mVerticalAccuracyMeters);
-        parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
-        parcel.writeFloat(mBearingAccuracyDegrees);
-        parcel.writeBundle(mExtras);
-    }
-
-    /**
-     * Returns one of the optional extra {@link Location}s that can be attached
-     * to this Location.
-     *
-     * @param key the key associated with the desired extra Location
-     * @return the extra Location, or null if unavailable
-     * @hide
-     */
-    public Location getExtraLocation(String key) {
-        if (mExtras != null) {
-            Parcelable value = mExtras.getParcelable(key);
-            if (value instanceof Location) {
-                return (Location) value;
-            }
+        if (hasAltitude()) {
+            parcel.writeDouble(mAltitude);
         }
-        return null;
+        if (hasSpeed()) {
+            parcel.writeFloat(mSpeed);
+        }
+        if (hasBearing()) {
+            parcel.writeFloat(mBearing);
+        }
+        if (hasAccuracy()) {
+            parcel.writeFloat(mHorizontalAccuracyMeters);
+        }
+        if (hasVerticalAccuracy()) {
+            parcel.writeFloat(mVerticalAccuracyMeters);
+        }
+        if (hasSpeedAccuracy()) {
+            parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
+        }
+        if (hasBearingAccuracy()) {
+            parcel.writeFloat(mBearingAccuracyDegrees);
+        }
+        parcel.writeBundle(mExtras);
     }
 
     /**
diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java
index 0ff0a72..523117b 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -46,6 +46,29 @@
     void onLocationChanged(@NonNull Location location);
 
     /**
+     * Called when the location has changed and locations are being delivered in batches. The
+     * default implementation calls through to ({@link #onLocationChanged(Location)} with all
+     * locations in the batch, from earliest to latest.
+     *
+     * @see LocationRequest#getMaxUpdateDelayMillis()
+     * @param locationResult the location result list
+     */
+    default void onLocationChanged(@NonNull LocationResult locationResult) {
+        final int size = locationResult.size();
+        for (int i = 0; i < size; ++i) {
+            onLocationChanged(locationResult.get(i));
+        }
+    }
+
+    /**
+     * Invoked when a flush operation is complete and after flushed locations have been delivered.
+     *
+     * @param requestCode the request code passed into
+     *                    {@link LocationManager#requestFlush(String, LocationListener, int)}
+     */
+    default void onFlushComplete(int requestCode) {}
+
+    /**
      * This callback will never be invoked on Android Q and above, and providers can be considered
      * as always in the {@link LocationProvider#AVAILABLE} state.
      *
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b61b79e..4fbcfe1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -33,6 +33,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -65,8 +66,8 @@
 
 import java.lang.ref.WeakReference;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.WeakHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -238,6 +239,22 @@
     public static final String KEY_LOCATION_CHANGED = "location";
 
     /**
+     * Key used for an extra holding a {@link LocationResult} value when a location change is sent
+     * using a PendingIntent.
+     *
+     * @see #requestLocationUpdates(String, LocationRequest, PendingIntent)
+     */
+    public static final String KEY_LOCATION_RESULT = "locationResult";
+
+    /**
+     * Key used for an extra holding an integer request code when location flush completion is sent
+     * using a PendingIntent.
+     *
+     * @see #requestFlush(String, PendingIntent, int)
+     */
+    public static final String KEY_FLUSH_COMPLETE = "flushComplete";
+
+    /**
      * Broadcast intent action when the set of enabled location providers changes. To check the
      * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
      * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
@@ -376,9 +393,6 @@
     @GuardedBy("mLock")
     @Nullable private GnssAntennaInfoTransportMultiplexer mGnssAntennaInfoTransportMultiplexer;
 
-    @GuardedBy("mLock")
-    @Nullable private BatchedLocationCallbackTransport mBatchedLocationCallbackTransport;
-
     /**
      * @hide
      */
@@ -1432,8 +1446,70 @@
     }
 
     /**
+     * Requests that the given provider flush any batched locations to listeners. The given listener
+     * (registered with the provider) will have {@link LocationListener#onFlushComplete(int)}
+     * invoked with the given result code after any locations that were flushed have been delivered.
+     * If {@link #removeUpdates(LocationListener)} is invoked before the flush callback is executed,
+     * then the flush callback will never be executed.
+     *
+     * @param provider    a provider listed by {@link #getAllProviders()}
+     * @param listener    a listener registered under the provider
+     * @param requestCode an arbitrary integer passed through to
+     *                    {@link LocationListener#onFlushComplete(int)}
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if listener is null or is not registered under the provider
+     */
+    @SuppressLint("SamShouldBeLast")
+    public void requestFlush(@NonNull String provider, @NonNull LocationListener listener,
+            @SuppressLint("ListenerLast") int requestCode) {
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
+
+        synchronized (sLocationListeners) {
+            WeakReference<LocationListenerTransport> ref = sLocationListeners.get(listener);
+            LocationListenerTransport transport = ref != null ? ref.get() : null;
+
+            Preconditions.checkArgument(transport != null,
+                    "unregistered listener cannot be flushed");
+
+            try {
+                mService.requestListenerFlush(provider, transport, requestCode);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Requests that the given provider flush any batched locations to listeners. The given
+     * PendingIntent (registered with the provider) will be sent with {@link #KEY_FLUSH_COMPLETE}
+     * present in the extra keys, and {@code requestCode} as the corresponding value.
+     *
+     * @param provider      a provider listed by {@link #getAllProviders()}
+     * @param pendingIntent a pendingIntent registered under the provider
+     * @param requestCode   an arbitrary integer that will be passed back as the extra value for
+     *                      {@link #KEY_FLUSH_COMPLETE}
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if pending intent is null or is not registered under the
+     *                                  provider
+     */
+    public void requestFlush(@NonNull String provider, @NonNull PendingIntent pendingIntent,
+            int requestCode) {
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
+        try {
+            mService.requestPendingIntentFlush(provider, pendingIntent, requestCode);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Removes location updates for the specified {@link LocationListener}. Following this call,
-     * the listener will no longer receive location updates.
+     * the listener will not receive any more invocations of any kind.
      *
      * @param listener listener that no longer needs location updates
      *
@@ -2435,10 +2511,11 @@
      * interface.
      *
      * @return Maximum number of location objects that can be returned
+     * @deprecated Do not use
      * @hide
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public int getGnssBatchSize() {
         try {
             return mService.getGnssBatchSize();
@@ -2458,48 +2535,47 @@
      *
      * @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested
      *                    within the batch
-     * @param wakeOnFifoFull True if the hardware batching should flush the locations in a
-     *                       a callback to the listener, when it's internal buffer is full.  If
-     *                       set to false, the oldest location information is, instead,
-     *                       dropped when the buffer is full.
+     * @param wakeOnFifoFull ignored
      * @param callback The listener on which to return the batched locations
      * @param handler The handler on which to process the callback
      *
-     * @return True if batching was successfully started
+     * @return True always
+     * @deprecated Use {@link LocationRequest.Builder#setMaxUpdateDelayMillis(long)} instead.
      * @hide
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    @RequiresPermission(allOf = {Manifest.permission.LOCATION_HARDWARE,
+            Manifest.permission.UPDATE_APP_OPS_STATS})
     public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
             @NonNull BatchedLocationCallback callback, @Nullable Handler handler) {
         if (handler == null) {
             handler = new Handler();
         }
 
-        BatchedLocationCallbackTransport transport = new BatchedLocationCallbackTransport(callback,
-                handler);
-
-        synchronized (mLock) {
-            try {
-                mService.setGnssBatchingCallback(transport, mContext.getPackageName(),
-                        mContext.getAttributionTag());
-                mBatchedLocationCallbackTransport = transport;
-                mService.startGnssBatch(periodNanos, wakeOnFifoFull,
-                        mContext.getPackageName(), mContext.getFeatureId());
-                return true;
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+        try {
+            mService.startGnssBatch(
+                    periodNanos,
+                    new BatchedLocationCallbackTransport(callback, handler),
+                    mContext.getPackageName(),
+                    mContext.getAttributionTag(),
+                    AppOpsManager.toReceiverId(callback));
+            return true;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Flush the batched GNSS locations.
-     * All GNSS locations currently ready in the batch are returned via the callback sent in
-     * startGnssBatch(), and the buffer containing the batched locations is cleared.
+     * Flush the batched GNSS locations. All GNSS locations currently ready in the batch are
+     * returned via the callback sent in startGnssBatch(), and the buffer containing the batched
+     * locations is cleared.
      *
      * @hide
+     * @deprecated Use {@link #requestFlush(String, LocationListener, int)} or
+     *             {@link #requestFlush(String, PendingIntent, int)} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public void flushGnssBatch() {
@@ -2511,29 +2587,25 @@
     }
 
     /**
-     * Stop batching locations. This API is primarily used when the AP is
-     * asleep and the device can batch locations in the hardware.
+     * Stop batching locations. This API is primarily used when the AP is asleep and the device can
+     * batch locations in the hardware.
      *
-     * @param callback the specific callback class to remove from the transport layer
+     * @param callback ignored
      *
      * @return True always
+     * @deprecated Use {@link LocationRequest.Builder#setMaxUpdateDelayMillis(long)} instead.
      * @hide
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
     public boolean unregisterGnssBatchedLocationCallback(
             @NonNull BatchedLocationCallback callback) {
-        synchronized (mLock) {
-            if (callback == mBatchedLocationCallbackTransport.getCallback()) {
-                try {
-                    mBatchedLocationCallbackTransport = null;
-                    mService.removeGnssBatchingCallback();
-                    mService.stopGnssBatch();
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
+        try {
+            mService.stopGnssBatch();
             return true;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2541,10 +2613,7 @@
             ListenerExecutor, CancellationSignal.OnCancelListener {
 
         private final Executor mExecutor;
-
-        @GuardedBy("this")
-        @Nullable
-        private Consumer<Location> mConsumer;
+        private volatile @Nullable Consumer<Location> mConsumer;
 
         GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer,
                 @Nullable CancellationSignal cancellationSignal) {
@@ -2560,20 +2629,22 @@
 
         @Override
         public void onCancel() {
-            synchronized (this) {
-                mConsumer = null;
-            }
+            mConsumer = null;
         }
 
         @Override
         public void onLocation(@Nullable Location location) {
-            Consumer<Location> consumer;
-            synchronized (this) {
-                consumer = mConsumer;
-                mConsumer = null;
-            }
+            executeSafely(mExecutor, () -> mConsumer, new ListenerOperation<Consumer<Location>>() {
+                @Override
+                public void operate(Consumer<Location> consumer) {
+                    consumer.accept(location);
+                }
 
-            executeSafely(mExecutor, () -> consumer, listener -> listener.accept(location));
+                @Override
+                public void onPostExecute(boolean success) {
+                    mConsumer = null;
+                }
+            });
         }
     }
 
@@ -2581,7 +2652,7 @@
             ListenerExecutor {
 
         private Executor mExecutor;
-        @Nullable private volatile LocationListener mListener;
+        private volatile @Nullable LocationListener mListener;
 
         LocationListenerTransport(LocationListener listener, Executor executor) {
             Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -2603,12 +2674,12 @@
         }
 
         @Override
-        public void onLocationChanged(Location location,
+        public void onLocationChanged(LocationResult locationResult,
                 @Nullable IRemoteCallback onCompleteCallback) {
             executeSafely(mExecutor, () -> mListener, new ListenerOperation<LocationListener>() {
                 @Override
                 public void operate(LocationListener listener) {
-                    listener.onLocationChanged(location);
+                    listener.onLocationChanged(locationResult);
                 }
 
                 @Override
@@ -2625,6 +2696,12 @@
         }
 
         @Override
+        public void onFlushComplete(int requestCode) {
+            executeSafely(mExecutor, () -> mListener,
+                    listener -> listener.onFlushComplete(requestCode));
+        }
+
+        @Override
         public void onProviderEnabledChanged(String provider, boolean enabled) {
             executeSafely(mExecutor, () -> mListener, listener -> {
                 if (enabled) {
@@ -2913,39 +2990,29 @@
         }
     }
 
-    private static class BatchedLocationCallbackTransport extends IBatchedLocationCallback.Stub {
+    private static class BatchedLocationCallbackWrapper implements LocationListener {
 
-        private final Handler mHandler;
-        private volatile @Nullable BatchedLocationCallback mCallback;
+        private final BatchedLocationCallback mCallback;
 
-        BatchedLocationCallbackTransport(BatchedLocationCallback callback, Handler handler) {
-            mCallback = Objects.requireNonNull(callback);
-            mHandler = Objects.requireNonNull(handler);
-        }
-
-        @Nullable
-        public BatchedLocationCallback getCallback() {
-            return mCallback;
-        }
-
-        public void unregister() {
-            mCallback = null;
+        BatchedLocationCallbackWrapper(BatchedLocationCallback callback) {
+            mCallback = callback;
         }
 
         @Override
-        public void onLocationBatch(List<Location> locations) {
-            if (mCallback == null) {
-                return;
-            }
+        public void onLocationChanged(@NonNull Location location) {
+            mCallback.onLocationBatch(Collections.singletonList(location));
+        }
 
-            mHandler.post(() -> {
-                BatchedLocationCallback callback = mCallback;
-                if (callback == null) {
-                    return;
-                }
+        @Override
+        public void onLocationChanged(@NonNull LocationResult locationResult) {
+            mCallback.onLocationBatch(locationResult.asList());
+        }
+    }
 
-                callback.onLocationBatch(locations);
-            });
+    private static class BatchedLocationCallbackTransport extends LocationListenerTransport {
+
+        BatchedLocationCallbackTransport(BatchedLocationCallback callback, Handler handler) {
+            super(new BatchedLocationCallbackWrapper(callback), new HandlerExecutor(handler));
         }
     }
 
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index ef68814..1027f9c 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,8 +21,6 @@
 import android.annotation.Nullable;
 import android.location.util.identity.CallerIdentity;
 
-import java.util.List;
-
 /**
  * Location manager local system service interface.
  *
@@ -82,10 +80,4 @@
      */
     // TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
     public abstract void sendNiResponse(int notifId, int userResponse);
-
-    /**
-     * Should only be used by GNSS code.
-     */
-    // TODO: there is no reason for this to exist as part of any API. create a real batching API
-    public abstract void reportGnssBatchLocations(List<Location> locations);
 }
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 1adb2b4..323e740 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -191,6 +191,7 @@
     private long mDurationMillis;
     private int mMaxUpdates;
     private float mMinUpdateDistanceMeters;
+    private final long mMaxUpdateDelayMillis;
     private boolean mHideFromAppOps;
     private boolean mLocationSettingsIgnored;
     private boolean mLowPower;
@@ -285,6 +286,7 @@
             int maxUpdates,
             long minUpdateIntervalMillis,
             float minUpdateDistanceMeters,
+            long maxUpdateDelayMillis,
             boolean hiddenFromAppOps,
             boolean locationSettingsIgnored,
             boolean lowPower,
@@ -297,6 +299,7 @@
         mDurationMillis = durationMillis;
         mMaxUpdates = maxUpdates;
         mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+        mMaxUpdateDelayMillis = maxUpdateDelayMillis;
         mHideFromAppOps = hiddenFromAppOps;
         mLowPower = lowPower;
         mLocationSettingsIgnored = locationSettingsIgnored;
@@ -592,6 +595,24 @@
     }
 
     /**
+     * Returns the maximum time any location update may be delayed, and thus grouped with following
+     * updates to enable location batching. If the maximum update delay is equal to or greater than
+     * twice the interval, then location providers may provide batched results. The maximum batch
+     * size is the maximum update delay divided by the interval. Not all devices or location
+     * providers support batching, and use of this parameter does not guarantee that the client will
+     * see batched results, or that batched results will always be of the maximum size.
+     *
+     * When available, batching can provide substantial power savings to the device, and clients are
+     * encouraged to take advantage where appropriate for the use case.
+     *
+     * @see LocationListener#onLocationChanged(LocationResult)
+     * @return the maximum time by which a location update may be delayed
+     */
+    public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
+        return mMaxUpdateDelayMillis;
+    }
+
+    /**
      * @hide
      * @deprecated LocationRequests should be treated as immutable.
      */
@@ -725,6 +746,7 @@
                             /* maxUpdates= */ in.readInt(),
                             /* minUpdateIntervalMillis= */ in.readLong(),
                             /* minUpdateDistanceMeters= */ in.readFloat(),
+                            /* maxUpdateDelayMillis= */ in.readLong(),
                             /* hiddenFromAppOps= */ in.readBoolean(),
                             /* locationSettingsIgnored= */ in.readBoolean(),
                             /* lowPower= */ in.readBoolean(),
@@ -752,6 +774,7 @@
         parcel.writeInt(mMaxUpdates);
         parcel.writeLong(mMinUpdateIntervalMillis);
         parcel.writeFloat(mMinUpdateDistanceMeters);
+        parcel.writeLong(mMaxUpdateDelayMillis);
         parcel.writeBoolean(mHideFromAppOps);
         parcel.writeBoolean(mLocationSettingsIgnored);
         parcel.writeBoolean(mLowPower);
@@ -775,6 +798,7 @@
                 && mMaxUpdates == that.mMaxUpdates
                 && mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
                 && Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
+                && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
                 && mHideFromAppOps == that.mHideFromAppOps
                 && mLocationSettingsIgnored == that.mLocationSettingsIgnored
                 && mLowPower == that.mLowPower
@@ -831,6 +855,10 @@
         if (mMinUpdateDistanceMeters > 0.0) {
             s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
         }
+        if (mMaxUpdateDelayMillis / 2 > mInterval) {
+            s.append(", maxUpdateDelay=");
+            TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
+        }
         if (mLowPower) {
             s.append(", lowPower");
         }
@@ -858,6 +886,7 @@
         private int mMaxUpdates;
         private long mMinUpdateIntervalMillis;
         private float mMinUpdateDistanceMeters;
+        private long mMaxUpdateDelayMillis;
         private boolean mHiddenFromAppOps;
         private boolean mLocationSettingsIgnored;
         private boolean mLowPower;
@@ -876,6 +905,7 @@
             mMaxUpdates = Integer.MAX_VALUE;
             mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
             mMinUpdateDistanceMeters = 0;
+            mMaxUpdateDelayMillis = 0;
             mHiddenFromAppOps = false;
             mLocationSettingsIgnored = false;
             mLowPower = false;
@@ -892,6 +922,7 @@
             mMaxUpdates = locationRequest.mMaxUpdates;
             mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
             mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
+            mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
             mHiddenFromAppOps = locationRequest.mHideFromAppOps;
             mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
             mLowPower = locationRequest.mLowPower;
@@ -1027,6 +1058,19 @@
         }
 
         /**
+         * Sets the maximum time any location update may be delayed, and thus grouped with following
+         * updates to enable location batching. If the maximum update delay is equal to or greater
+         * than twice the interval, then location providers may provide batched results. Defaults to
+         * 0, which represents no batching allowed.
+         */
+        public @NonNull Builder setMaxUpdateDelayMillis(
+                @IntRange(from = 0) long maxUpdateDelayMillis) {
+            mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
+                    Long.MAX_VALUE, "maxUpdateDelayMillis");
+            return this;
+        }
+
+        /**
          * If set to true, indicates that app ops should not be updated with location usage due to
          * this request. This implies that someone else (usually the creator of the location
          * request) is responsible for updating app ops as appropriate. Defaults to false.
@@ -1121,6 +1165,7 @@
                     mMaxUpdates,
                     min(mMinUpdateIntervalMillis, mIntervalMillis),
                     mMinUpdateDistanceMeters,
+                    mMaxUpdateDelayMillis,
                     mHiddenFromAppOps,
                     mLocationSettingsIgnored,
                     mLowPower,
diff --git a/location/java/android/location/IBatchedLocationCallback.aidl b/location/java/android/location/LocationResult.aidl
similarity index 65%
rename from location/java/android/location/IBatchedLocationCallback.aidl
rename to location/java/android/location/LocationResult.aidl
index dce9f96..3bb894f 100644
--- a/location/java/android/location/IBatchedLocationCallback.aidl
+++ b/location/java/android/location/LocationResult.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2017, The Android Open Source Project
+ * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,14 +16,4 @@
 
 package android.location;
 
-import android.location.Location;
-
-import java.util.List;
-
-/**
- * {@hide}
- */
-oneway interface IBatchedLocationCallback
-{
-    void onLocationBatch(in List<Location> locations);
-}
+parcelable LocationResult;
diff --git a/location/java/android/location/LocationResult.java b/location/java/android/location/LocationResult.java
new file mode 100644
index 0000000..79a000c
--- /dev/null
+++ b/location/java/android/location/LocationResult.java
@@ -0,0 +1,273 @@
+/*
+ * 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.location;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * A location result representing a list of locations, ordered from earliest to latest.
+ */
+public final class LocationResult implements Parcelable {
+
+    /**
+     * Creates a new LocationResult from the given location.
+     */
+    public static @NonNull LocationResult create(@NonNull Location location) {
+        ArrayList<Location> locations = new ArrayList<>(1);
+        locations.add(new Location(Objects.requireNonNull(location)));
+        return new LocationResult(locations);
+    }
+
+    /**
+     * Creates a new LocationResult from the given locations. Locations must be ordered in the same
+     * order they were derived (earliest to latest).
+     */
+    public static @NonNull LocationResult create(@NonNull List<Location> locations) {
+        Preconditions.checkArgument(!locations.isEmpty());
+        ArrayList<Location> locationsCopy = new ArrayList<>(locations.size());
+        for (Location location : locations) {
+            locationsCopy.add(new Location(Objects.requireNonNull(location)));
+        }
+        return new LocationResult(locationsCopy);
+    }
+
+    /**
+     * Creates a new LocationResult that takes ownership of the given location without copying it.
+     * Callers must ensure the given location is never mutated after this method is called.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static @NonNull LocationResult wrap(@NonNull Location location) {
+        ArrayList<Location> locations = new ArrayList<>(1);
+        locations.add(Objects.requireNonNull(location));
+        return new LocationResult(locations);
+    }
+
+    private final ArrayList<Location> mLocations;
+
+    private LocationResult(ArrayList<Location> locations) {
+        Preconditions.checkArgument(!locations.isEmpty());
+        mLocations = locations;
+    }
+
+    /**
+     * Throws an IllegalArgumentException if the ordering of locations does not appear to generally
+     * be from earliest to latest, or if any individual location is incomplete.
+     *
+     * @hide
+     */
+    public @NonNull LocationResult validate() {
+        long prevElapsedRealtimeNs = 0;
+        final int size = mLocations.size();
+        for (int i = 0; i < size; ++i) {
+            Location location = mLocations.get(i);
+            if (!location.isComplete()) {
+                throw new IllegalArgumentException(
+                        "incomplete location at index " + i + ": " + mLocations);
+            }
+            if (location.getElapsedRealtimeNanos() < prevElapsedRealtimeNs) {
+                throw new IllegalArgumentException(
+                        "incorrectly ordered location at index " + i + ": " + mLocations);
+            }
+            prevElapsedRealtimeNs = location.getElapsedRealtimeNanos();
+        }
+
+        return this;
+    }
+
+    /**
+     * Returns the latest location in this location result, ie, the location at the highest index.
+     */
+    public @NonNull Location getLastLocation() {
+        return mLocations.get(mLocations.size() - 1);
+    }
+
+    /**
+     * Returns the numer of locations in this location result.
+     */
+    public @IntRange(from = 1) int size() {
+        return mLocations.size();
+    }
+
+    /**
+     * Returns the location at the given index, from 0 to {@link #size()} - 1. Locations at lower
+     * indices are from earlier in time than location at higher indices.
+     */
+    public @NonNull Location get(@IntRange(from = 0) int i) {
+        return mLocations.get(i);
+    }
+
+    /**
+     * Returns an unmodifiable list of locations in this location result.
+     */
+    public @NonNull List<Location> asList() {
+        return Collections.unmodifiableList(mLocations);
+    }
+
+    /**
+     * Returns a deep copy of this LocationResult.
+     *
+     * @hide
+     */
+    public @NonNull LocationResult deepCopy() {
+        ArrayList<Location> copy = new ArrayList<>(mLocations.size());
+        final int size = mLocations.size();
+        for (int i = 0; i < size; ++i) {
+            copy.add(new Location(mLocations.get(i)));
+        }
+        return new LocationResult(copy);
+    }
+
+    /**
+     * Returns a LocationResult with only the last location from this location result.
+     *
+     * @hide
+     */
+    public @NonNull LocationResult asLastLocationResult() {
+        if (mLocations.size() == 1) {
+            return this;
+        } else {
+            return LocationResult.wrap(getLastLocation());
+        }
+    }
+
+    /**
+     * Returns a LocationResult with only locations that pass the given predicate. This
+     * implementation will avoid allocations when no locations are filtered out. The predicate is
+     * guaranteed to be invoked once per location, in order from earliest to latest. If all
+     * locations are filtered out a null value is returned instead of an empty LocationResult.
+     *
+     * @hide
+     */
+    public @Nullable LocationResult filter(Predicate<Location> predicate) {
+        ArrayList<Location> filtered = mLocations;
+        final int size = mLocations.size();
+        for (int i = 0; i < size; ++i) {
+            if (!predicate.test(mLocations.get(i))) {
+                if (filtered == mLocations) {
+                    filtered = new ArrayList<>(mLocations.size() - 1);
+                    for (int j = 0; j < i; ++j) {
+                        filtered.add(mLocations.get(j));
+                    }
+                }
+            } else if (filtered != mLocations) {
+                filtered.add(mLocations.get(i));
+            }
+        }
+
+        if (filtered == mLocations) {
+            return this;
+        } else if (filtered.isEmpty()) {
+            return null;
+        } else {
+            return new LocationResult(filtered);
+        }
+    }
+
+    /**
+     * Returns a LocationResult with locations mapped to other locations. This implementation will
+     * avoid allocations when all locations are mapped to the same location. The function is
+     * guaranteed to be invoked once per location, in order from earliest to latest.
+     *
+     * @hide
+     */
+    public @NonNull LocationResult map(Function<Location, Location> function) {
+        ArrayList<Location> mapped = mLocations;
+        final int size = mLocations.size();
+        for (int i = 0; i < size; ++i) {
+            Location location = mLocations.get(i);
+            Location newLocation = function.apply(location);
+            if (mapped != mLocations) {
+                mapped.add(newLocation);
+            } else if (newLocation != location) {
+                mapped = new ArrayList<>(mLocations.size());
+                for (int j = 0; j < i; ++j) {
+                    mapped.add(mLocations.get(j));
+                }
+                mapped.add(newLocation);
+            }
+        }
+
+        if (mapped == mLocations) {
+            return this;
+        } else {
+            return new LocationResult(mapped);
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<LocationResult> CREATOR =
+            new Parcelable.Creator<LocationResult>() {
+                @Override
+                public LocationResult createFromParcel(Parcel in) {
+                    return new LocationResult(
+                            Objects.requireNonNull(in.createTypedArrayList(Location.CREATOR)));
+                }
+
+                @Override
+                public LocationResult[] newArray(int size) {
+                    return new LocationResult[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeTypedList(mLocations);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        LocationResult that = (LocationResult) o;
+        return mLocations.equals(that.mLocations);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLocations);
+    }
+
+    @Override
+    public String toString() {
+        return mLocations.toString();
+    }
+}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index 01570dc..dac08ff 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -35,6 +35,8 @@
     @UnsupportedAppUsage(maxTargetSdk = 30, publicAlternatives = "{@code Do not use}")
     oneway void setRequest(in ProviderRequest request, in WorkSource ws);
 
+    oneway void flush();
+
     @UnsupportedAppUsage(maxTargetSdk = 30, publicAlternatives = "{@code Do not use}")
     oneway void sendExtraCommand(String command, in Bundle extras);
 }
diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
index 2a6cef8..a74538b 100644
--- a/location/java/com/android/internal/location/ILocationProviderManager.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -16,7 +16,7 @@
 
 package com.android.internal.location;
 
-import android.location.Location;
+import android.location.LocationResult;
 
 import com.android.internal.location.ProviderProperties;
 
@@ -28,5 +28,6 @@
     void onSetIdentity(@nullable String packageName, @nullable String attributionTag);
     void onSetAllowed(boolean allowed);
     void onSetProperties(in ProviderProperties properties);
-    void onReportLocation(in Location location);
+    void onReportLocation(in LocationResult locationResult);
+    void onFlushComplete();
 }
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index 00ba552..545ea52 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -46,7 +46,7 @@
     public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
 
     public static final ProviderRequest EMPTY_REQUEST = new ProviderRequest(
-            INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, false, false, new WorkSource());
+            INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, 0, false, false, new WorkSource());
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
             + "ProviderRequest}")
@@ -55,6 +55,7 @@
             + "ProviderRequest}")
     public final long interval;
     private final @Quality int mQuality;
+    private final long mMaxUpdateDelayMillis;
     private final boolean mLowPower;
     private final boolean mLocationSettingsIgnored;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
@@ -62,11 +63,17 @@
     public final List<LocationRequest> locationRequests;
     private final WorkSource mWorkSource;
 
-    private ProviderRequest(long intervalMillis, @Quality int quality, boolean lowPower,
-            boolean locationSettingsIgnored, @NonNull WorkSource workSource) {
+    private ProviderRequest(
+            long intervalMillis,
+            @Quality int quality,
+            long maxUpdateDelayMillis,
+            boolean lowPower,
+            boolean locationSettingsIgnored,
+            @NonNull WorkSource workSource) {
         reportLocation = intervalMillis != INTERVAL_DISABLED;
         interval = intervalMillis;
         mQuality = quality;
+        mMaxUpdateDelayMillis = maxUpdateDelayMillis;
         mLowPower = lowPower;
         mLocationSettingsIgnored = locationSettingsIgnored;
         if (intervalMillis != INTERVAL_DISABLED) {
@@ -108,6 +115,17 @@
     }
 
     /**
+     * The maximum time any location update may be delayed, and thus grouped with following updates
+     * to enable location batching. If the maximum update delay is equal to or greater than
+     * twice the interval, then the provider may provide batched results if possible. The maximum
+     * batch size a provider is allowed to return is the maximum update delay divided by the
+     * interval.
+     */
+    public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
+        return mMaxUpdateDelayMillis;
+    }
+
+    /**
      * Whether any applicable hardware low power modes should be used to satisfy this request.
      */
     public boolean isLowPower() {
@@ -141,6 +159,7 @@
                         return new ProviderRequest(
                                 intervalMillis,
                                 /* quality= */ in.readInt(),
+                                /* maxUpdateDelayMillis= */ in.readLong(),
                                 /* lowPower= */ in.readBoolean(),
                                 /* locationSettingsIgnored= */ in.readBoolean(),
                                 /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
@@ -163,6 +182,7 @@
         parcel.writeLong(interval);
         if (interval != INTERVAL_DISABLED) {
             parcel.writeInt(mQuality);
+            parcel.writeLong(mMaxUpdateDelayMillis);
             parcel.writeBoolean(mLowPower);
             parcel.writeBoolean(mLocationSettingsIgnored);
             parcel.writeTypedObject(mWorkSource, flags);
@@ -184,6 +204,7 @@
         } else {
             return interval == that.interval
                     && mQuality == that.mQuality
+                    && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
                     && mLowPower == that.mLowPower
                     && mLocationSettingsIgnored == that.mLocationSettingsIgnored
                     && mWorkSource.equals(that.mWorkSource);
@@ -209,6 +230,10 @@
                     s.append(", LOW_POWER");
                 }
             }
+            if (mMaxUpdateDelayMillis / 2 > interval) {
+                s.append(", maxUpdateDelay=");
+                TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
+            }
             if (mLowPower) {
                 s.append(", lowPower");
             }
@@ -231,6 +256,7 @@
     public static class Builder {
         private long mIntervalMillis = INTERVAL_DISABLED;
         private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
+        private long mMaxUpdateDelayMillis = 0;
         private boolean mLowPower;
         private boolean mLocationSettingsIgnored;
         private WorkSource mWorkSource = new WorkSource();
@@ -260,6 +286,19 @@
         }
 
         /**
+         * Sets the maximum time any location update may be delayed, and thus grouped with following
+         * updates to enable location batching. If the maximum update delay is equal to or greater
+         * than twice the interval, then location providers may provide batched results. Defaults to
+         * 0.
+         */
+        public @NonNull Builder setMaxUpdateDelayMillis(
+                @IntRange(from = 0) long maxUpdateDelayMillis) {
+            mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
+                    Long.MAX_VALUE, "maxUpdateDelayMillis");
+            return this;
+        }
+
+        /**
          * Sets whether hardware low power mode should be used. False by default.
          */
         public @NonNull Builder setLowPower(boolean lowPower) {
@@ -290,8 +329,13 @@
             if (mIntervalMillis == INTERVAL_DISABLED) {
                 return EMPTY_REQUEST;
             } else {
-                return new ProviderRequest(mIntervalMillis, mQuality, mLowPower,
-                        mLocationSettingsIgnored, mWorkSource);
+                return new ProviderRequest(
+                        mIntervalMillis,
+                        mQuality,
+                        mMaxUpdateDelayMillis,
+                        mLowPower,
+                        mLocationSettingsIgnored,
+                        mWorkSource);
             }
         }
     }
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 80636c6..d4f7558 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -15,12 +15,14 @@
     method @Deprecated protected void onDisable();
     method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
     method @Deprecated protected void onEnable();
+    method protected void onFlush(com.android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
     method @Deprecated protected int onGetStatus(android.os.Bundle);
     method @Deprecated protected long onGetStatusUpdateTime();
     method protected void onInit();
     method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
     method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
     method public void reportLocation(android.location.Location);
+    method public void reportLocation(android.location.LocationResult);
     method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>);
     method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean);
     method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean);
@@ -29,6 +31,10 @@
     field public static final String FUSED_PROVIDER = "fused";
   }
 
+  protected static interface LocationProviderBase.OnFlushCompleteCallback {
+    method public void onFlushComplete();
+  }
+
   @Deprecated public final class LocationRequestUnbundled {
     method @Deprecated public long getFastestInterval();
     method @Deprecated public long getInterval();
@@ -50,6 +56,7 @@
   public final class ProviderRequestUnbundled {
     method public long getInterval();
     method @Deprecated @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+    method @RequiresApi(android.os.Build.VERSION_CODES.S) public long getMaxUpdateDelayMillis();
     method @android.location.LocationRequest.Quality @RequiresApi(android.os.Build.VERSION_CODES.S) public int getQuality();
     method public boolean getReportLocation();
     method @NonNull @RequiresApi(android.os.Build.VERSION_CODES.S) public android.os.WorkSource getWorkSource();
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 32ac374b..54d8066 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -22,6 +22,7 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationProvider;
+import android.location.LocationResult;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -61,6 +62,18 @@
 public abstract class LocationProviderBase {
 
     /**
+     * Callback to be invoked when a flush operation is complete and all flushed locations have been
+     * reported.
+     */
+    protected interface OnFlushCompleteCallback {
+
+        /**
+         * Should be invoked once the flush is complete.
+         */
+        void onFlushComplete();
+    }
+
+    /**
      * Bundle key for a version of the location containing no GPS data.
      * Allows location providers to flag locations as being safe to
      * feed to LocationFudger.
@@ -235,23 +248,33 @@
      * Reports a new location from this provider.
      */
     public void reportLocation(Location location) {
+        reportLocation(LocationResult.create(location));
+    }
+
+    /**
+     * Reports a new location from this provider.
+     */
+    public void reportLocation(LocationResult locationResult) {
         ILocationProviderManager manager = mManager;
         if (manager != null) {
-            // remove deprecated extras to save on serialization
-            Bundle extras = location.getExtras();
-            if (extras != null && (extras.containsKey("noGPSLocation")
-                    || extras.containsKey("coarseLocation"))) {
-                location = new Location(location);
-                extras = location.getExtras();
-                extras.remove("noGPSLocation");
-                extras.remove("coarseLocation");
-                if (extras.isEmpty()) {
-                    location.setExtras(null);
+            locationResult = locationResult.map(location -> {
+                // remove deprecated extras to save on serialization costs
+                Bundle extras = location.getExtras();
+                if (extras != null && (extras.containsKey("noGPSLocation")
+                        || extras.containsKey("coarseLocation"))) {
+                    location = new Location(location);
+                    extras = location.getExtras();
+                    extras.remove("noGPSLocation");
+                    extras.remove("coarseLocation");
+                    if (extras.isEmpty()) {
+                        location.setExtras(null);
+                    }
                 }
-            }
+                return location;
+            });
 
             try {
-                manager.onReportLocation(location);
+                manager.onReportLocation(locationResult);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             } catch (RuntimeException e) {
@@ -292,6 +315,16 @@
     protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
 
     /**
+     * Requests a flush of any pending batched locations. The callback must always be invoked once
+     * per invocation, and should be invoked after {@link #reportLocation(LocationResult)} has been
+     * invoked with any flushed locations. The callback may be invoked immediately if no locations
+     * are flushed.
+     */
+    protected void onFlush(OnFlushCompleteCallback callback) {
+        callback.onFlushComplete();
+    }
+
+    /**
      * @deprecated This callback will never be invoked on Android Q and above. This method may be
      * removed in the future. Prefer to dump provider state via the containing service instead.
      */
@@ -362,6 +395,24 @@
         }
 
         @Override
+        public void flush() {
+            onFlush(this::onFlushComplete);
+        }
+
+        private void onFlushComplete() {
+            ILocationProviderManager manager = mManager;
+            if (manager != null) {
+                try {
+                    manager.onFlushComplete();
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                } catch (RuntimeException e) {
+                    Log.w(mTag, e);
+                }
+            }
+        }
+
+        @Override
         public void sendExtraCommand(String command, Bundle extras) {
             onSendExtraCommand(command, extras);
         }
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index f7bac74..b464fca 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -57,6 +57,14 @@
     }
 
     /**
+     * The interval at which a provider should report location. Will return
+     * {@link #INTERVAL_DISABLED} for an inactive request.
+     */
+    public long getInterval() {
+        return mRequest.getIntervalMillis();
+    }
+
+    /**
      * The quality hint for this location request. The quality hint informs the provider how it
      * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
      * provider request.
@@ -67,11 +75,15 @@
     }
 
     /**
-     * The interval at which a provider should report location. Will return
-     * {@link #INTERVAL_DISABLED} for an inactive request.
+     * The maximum time any location update may be delayed, and thus grouped with following updates
+     * to enable location batching. If the maximum update delay is equal to or greater than
+     * twice the interval, then the provider may provide batched results if possible. The maximum
+     * batch size a provider is allowed to return is the maximum update delay divided by the
+     * interval.
      */
-    public long getInterval() {
-        return mRequest.getIntervalMillis();
+    @RequiresApi(Build.VERSION_CODES.S)
+    public long getMaxUpdateDelayMillis() {
+        return mRequest.getMaxUpdateDelayMillis();
     }
 
     /**
diff --git a/media/java/android/media/permission/PermissionUtil.java b/media/java/android/media/permission/PermissionUtil.java
index 458f112..315ee4f 100644
--- a/media/java/android/media/permission/PermissionUtil.java
+++ b/media/java/android/media/permission/PermissionUtil.java
@@ -17,10 +17,8 @@
 package android.media.permission;
 
 import android.annotation.NonNull;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.PermissionChecker;
-import android.content.pm.PackageManager;
 import android.os.Binder;
 
 import java.util.Objects;
@@ -180,57 +178,6 @@
     }
 
     /**
-     * Checks whether the given identity has the given permission to receive data.
-     *
-     * This variant ignores the proc-state for the sake of the check, i.e. overrides any
-     * restrictions that apply specifically to apps running in the background.
-     *
-     * TODO(ytai): This is a temporary hack until we have permissions that are specifically intended
-     *  for background microphone access.
-     *
-     * @param context    A {@link Context}, used for permission checks.
-     * @param identity   The identity to check.
-     * @param permission The identifier of the permission we want to check.
-     * @param reason     The reason why we're requesting the permission, for auditing purposes.
-     * @return The permission check result which is either
-     * {@link PermissionChecker#PERMISSION_GRANTED}
-     * or {@link PermissionChecker#PERMISSION_SOFT_DENIED} or
-     * {@link PermissionChecker#PERMISSION_HARD_DENIED}.
-     */
-    public static int checkPermissionForDataDeliveryIgnoreProcState(@NonNull Context context,
-            @NonNull Identity identity,
-            @NonNull String permission,
-            @NonNull String reason) {
-        if (context.checkPermission(permission, identity.pid, identity.uid)
-                != PackageManager.PERMISSION_GRANTED) {
-            return PermissionChecker.PERMISSION_HARD_DENIED;
-        }
-
-        String appOpOfPermission = AppOpsManager.permissionToOp(permission);
-        if (appOpOfPermission == null) {
-            // not platform defined
-            return PermissionChecker.PERMISSION_GRANTED;
-        }
-
-        String packageName = identity.packageName;
-        if (packageName == null) {
-            String[] packageNames = context.getPackageManager().getPackagesForUid(identity.uid);
-            if (packageNames != null && packageNames.length > 0) {
-                packageName = packageNames[0];
-            }
-        }
-
-        final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
-
-        int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpOfPermission, identity.uid,
-                packageName);
-        if (appOpMode == AppOpsManager.MODE_ALLOWED) {
-            return PermissionChecker.PERMISSION_GRANTED;
-        }
-        return PermissionChecker.PERMISSION_SOFT_DENIED;
-    }
-
-    /**
      * Checks whether the given identity has the given permission.
      *
      * @param context    A {@link Context}, used for permission checks.
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 38e2bdf..e9bb7f8 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
@@ -32,6 +33,7 @@
 import android.media.VolumeProvider.ControlType;
 import android.media.session.MediaSession.QueueItem;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -462,10 +464,11 @@
     }
 
     /**
+     * @hide
      * Returns whether this and {@code other} media controller controls the same session.
-     * @deprecated Check equality of {@link #getSessionToken() tokens} instead.
      */
-    @Deprecated
+    @UnsupportedAppUsage(publicAlternatives = "Check equality of {@link #getSessionToken() tokens} "
+            + "instead.", maxTargetSdk = Build.VERSION_CODES.R)
     public boolean controlsSameSession(@Nullable MediaController other) {
         if (other == null) return false;
         return mToken.equals(other.mToken);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index b596555..36158b7 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -32,6 +32,7 @@
 import android.media.MediaFrameworkInitializer;
 import android.media.MediaSession2;
 import android.media.Session2Token;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -209,7 +210,10 @@
      * @return A list of controllers for ongoing sessions.
      * @hide
      */
-    @UnsupportedAppUsage
+    // TODO: Remove @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Should only be"
+            + " used by system apps, since non-system apps cannot get other users' sessions."
+            + " Use {@link #getActiveSessions} instead.")
     public @NonNull List<MediaController> getActiveSessionsForUser(
             @Nullable ComponentName notificationListener, int userId) {
         ArrayList<MediaController> controllers = new ArrayList<MediaController>();
diff --git a/media/java/android/media/tv/tuner/Descrambler.java b/media/java/android/media/tv/tuner/Descrambler.java
index 7b58bfc3..5f79dc5 100644
--- a/media/java/android/media/tv/tuner/Descrambler.java
+++ b/media/java/android/media/tv/tuner/Descrambler.java
@@ -111,10 +111,13 @@
     /**
      * Set a key token to link descrambler to a key slot
      *
-     * A descrambler instance can have only one key slot to link, but a key slot can hold a few
+     * <p>A descrambler instance can have only one key slot to link, but a key slot can hold a few
      * keys for different purposes.
      *
-     * @param keyToken the token to be used to link the key slot.
+     * @param keyToken the token to be used to link the key slot. Use {@link Tuner.INVALID_KEYTOKEN}
+     *        to remove the to remove the current key from descrambler. If the current keyToken
+     *        comes from MediaCas session, use {@link Tuner.INVALID_KEYTOKEN} to remove current key
+     *        before close MediaCas session.
      * @return result status of the operation.
      */
     @Result
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 5a578dd..aa3143f 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -152,6 +152,27 @@
      */
     public static final int INVALID_FRONTEND_SETTING_FREQUENCY =
             android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
+    /**
+     * Invalid frontend id.
+     */
+    public static final int INVALID_FRONTEND_ID =
+            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_ID;
+    /**
+     * Invalid LNB id.
+     *
+     * @hide
+     */
+    public static final int INVALID_LNB_ID =
+            android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LNB_ID;
+    /**
+     * Invalid key token. It is used to remove the current key from descrambler.
+     *
+     * <p>If the current keyToken comes from a MediaCas session, App is recommended to
+     * to use this constant to remove current key before closing MediaCas session.
+     */
+    @NonNull
+    public static final byte[] INVALID_KEYTOKEN =
+            {android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_KEYTOKEN};
 
     /** @hide */
     @IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND})
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index f0abce9..1031e33 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -21,7 +21,7 @@
 import android.media.tv.tuner.filter.RecordSettings.ScHevcIndex;
 
 /**
- * Filter event sent from {@link Filter} objects with MMTP type.
+ * Filter event sent from {@link Filter} objects with MPEG media Transport Protocol(MMTP) type.
  *
  * @hide
  */
@@ -32,15 +32,17 @@
     private final int mMpuSequenceNumber;
     private final long mPts;
     private final int mFirstMbInSlice;
+    private final int mTsIndexMask;
 
     // This constructor is used by JNI code only
     private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts,
-            int firstMbInSlice) {
+            int firstMbInSlice, int tsIndexMask) {
         mScHevcIndexMask = scHevcIndexMask;
         mDataLength = dataLength;
         mMpuSequenceNumber = mpuSequenceNumber;
         mPts = pts;
         mFirstMbInSlice = firstMbInSlice;
+        mTsIndexMask = tsIndexMask;
     }
 
     /**
@@ -95,4 +97,17 @@
     public int getFirstMbInSlice() {
         return mFirstMbInSlice;
     }
+
+    /**
+     * Get the offset of the recorded keyframe from MMT Packet Table.
+     *
+     * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+     * return {@link RecordSettings.TS_INDEX_INVALID}. Use
+     * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the
+     * version information.
+     */
+    @RecordSettings.TsIndexMask
+    public int getTsIndexMask() {
+        return mTsIndexMask;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index a6fd20e..52ce208 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -38,17 +38,23 @@
      * @hide
      */
     @IntDef(flag = true,
-            prefix = "TS_INDEX_",
-            value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+            value = {TS_INDEX_INVALID, TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
                     TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
                     TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
                     TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR,
                     TS_INDEX_PCR_FLAG, TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG,
-                    TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+                    TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG,
+                    MPT_INDEX_MPT, MPT_INDEX_VIDEO, MPT_INDEX_AUDIO,
+                    MPT_INDEX_TIMESTAMP_TARGET_VIDEO,
+                    MPT_INDEX_TIMESTAMP_TARGET_AUDIO})
     @Retention(RetentionPolicy.SOURCE)
     public @interface TsIndexMask {}
 
     /**
+     * Invalid TS index.
+     */
+    public static final int TS_INDEX_INVALID = 0;
+    /**
      * TS index FIRST_PACKET.
      */
     public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
@@ -108,6 +114,32 @@
      */
     public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
             Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+    /**
+     * Index the address of MPEG Media Transport Packet Table(MPT).
+     */
+    public static final int MPT_INDEX_MPT =
+            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_MPT;
+    /**
+     * Index the address of Video.
+     */
+    public static final int MPT_INDEX_VIDEO =
+            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_VIDEO;
+    /**
+     * Index the address of Audio.
+     */
+    public static final int MPT_INDEX_AUDIO =
+            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_AUDIO;
+    /**
+     * Index to indicate this is a target of timestamp extraction for video.
+     */
+    public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO =
+            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_VIDEO;
+    /**
+     * Index to indicate this is a target of timestamp extraction for audio.
+     */
+    public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO =
+            android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_AUDIO;
+
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
index faa5434..948f4a7 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
@@ -26,10 +26,10 @@
 @SystemApi
 public class DvbcFrontendCapabilities extends FrontendCapabilities {
     private final int mModulationCap;
-    private final int mFecCap;
+    private final long mFecCap;
     private final int mAnnexCap;
 
-    private DvbcFrontendCapabilities(int modulationCap, int fecCap, int annexCap) {
+    private DvbcFrontendCapabilities(int modulationCap, long fecCap, int annexCap) {
         mModulationCap = modulationCap;
         mFecCap = fecCap;
         mAnnexCap = annexCap;
@@ -44,9 +44,24 @@
     }
     /**
      * Gets inner FEC capability.
+     *
+     * @deprecated Use {@link getInnerFecCapability()} with long return value instead. This function
+     *             returns the correct cap value when the value is not bigger than the max integer
+     *             value. Otherwise it returns {@link FrontendSettings#FEC_UNDEFINED}.
      */
+    @Deprecated
     @FrontendSettings.InnerFec
     public int getFecCapability() {
+        if (mFecCap > Integer.MAX_VALUE) {
+            return (int) FrontendSettings.FEC_UNDEFINED;
+        }
+        return (int) mFecCap;
+    }
+    /**
+     * Gets code rate capability.
+     */
+    @FrontendSettings.InnerFec
+    public long getCodeRateCapability() {
         return mFecCap;
     }
     /**
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index 334900b..68c0c96 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -53,6 +53,9 @@
 
     /**
      * Gets frontend ID.
+     *
+     * @return the frontend ID or {@link android.media.tv.tuner.Tuner.INVALID_FRONTEND_ID}
+     *         if invalid
      */
     public int getId() {
         return mId;
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index c93e079..af1ff01 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -51,7 +51,9 @@
             FRONTEND_STATUS_TYPE_TRANSMISSION_MODE, FRONTEND_STATUS_TYPE_UEC,
             FRONTEND_STATUS_TYPE_T2_SYSTEM_ID, FRONTEND_STATUS_TYPE_INTERLEAVINGS,
             FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS, FRONTEND_STATUS_TYPE_TS_DATA_RATES,
-            FRONTEND_STATUS_TYPE_MODULATIONS_EXT})
+            FRONTEND_STATUS_TYPE_MODULATIONS_EXT, FRONTEND_STATUS_TYPE_ROLL_OFF,
+            FRONTEND_STATUS_TYPE_IS_MISO, FRONTEND_STATUS_TYPE_IS_LINEAR,
+            FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendStatusType {}
 
@@ -208,6 +210,26 @@
      */
     public static final int FRONTEND_STATUS_TYPE_MODULATIONS_EXT =
             android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.MODULATIONS;
+    /**
+     * Roll Off Type status of the frontend. Only supported in Tuner HAL 1.1 or higher.
+     */
+    public static final int FRONTEND_STATUS_TYPE_ROLL_OFF =
+            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.ROLL_OFF;
+    /**
+     * If the frontend currently supports MISO or not. Only supported in Tuner HAL 1.1 or higher.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IS_MISO =
+            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_MISO;
+    /**
+     * If the frontend code rate is linear or not. Only supported in Tuner HAL 1.1 or higher.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IS_LINEAR =
+            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_LINEAR;
+    /**
+     * If short frames is enabled or not. Only supported in Tuner HAL 1.1 or higher.
+     */
+    public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES =
+            android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_SHORT_FRAMES;
 
     /** @hide */
     @IntDef(value = {
@@ -379,6 +401,22 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendGuardInterval {}
 
+    /** @hide */
+    @IntDef(value = {
+            DvbsFrontendSettings.ROLLOFF_UNDEFINED,
+            DvbsFrontendSettings.ROLLOFF_0_35,
+            DvbsFrontendSettings.ROLLOFF_0_25,
+            DvbsFrontendSettings.ROLLOFF_0_20,
+            DvbsFrontendSettings.ROLLOFF_0_15,
+            DvbsFrontendSettings.ROLLOFF_0_10,
+            DvbsFrontendSettings.ROLLOFF_0_5,
+            Isdbs3FrontendSettings.ROLLOFF_UNDEFINED,
+            Isdbs3FrontendSettings.ROLLOFF_0_03,
+            IsdbsFrontendSettings.ROLLOFF_UNDEFINED,
+            IsdbsFrontendSettings.ROLLOFF_0_35})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FrontendRollOff {}
+
     private Boolean mIsDemodLocked;
     private Integer mSnr;
     private Integer mBer;
@@ -412,6 +450,10 @@
     private int[] mTsDataRate;
     private int[] mIsdbtSegment;
     private int[] mModulationsExt;
+    private Integer mRollOff;
+    private Boolean mIsMisoEnabled;
+    private Boolean mIsLinear;
+    private Boolean mIsShortFrames;
 
 
     // Constructed and fields set by JNI code.
@@ -817,6 +859,67 @@
     }
 
     /**
+     * Gets roll off status.
+     *
+     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+     */
+    @FrontendRollOff
+    public int getRollOff() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_1_1, "getRollOff status");
+        if (mRollOff == null) {
+            throw new IllegalStateException();
+        }
+        return mRollOff;
+    }
+
+    /**
+     * Gets is MISO enabled status.
+     *
+     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+     */
+    public boolean isMisoEnabled() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_1_1, "isMisoEnabled status");
+        if (mIsMisoEnabled == null) {
+            throw new IllegalStateException();
+        }
+        return mIsMisoEnabled;
+    }
+
+    /**
+     * Gets is the Code Rate of the frontend is linear or not status.
+     *
+     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+     */
+    public boolean isLinear() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_1_1, "isLinear status");
+        if (mIsLinear == null) {
+            throw new IllegalStateException();
+        }
+        return mIsLinear;
+    }
+
+    /**
+     * Gets is the Short Frames enabled or not status.
+     *
+     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+     */
+    public boolean isShortFramesEnabled() {
+        TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_1_1, "isShortFramesEnabled status");
+        if (mIsShortFrames == null) {
+            throw new IllegalStateException();
+        }
+        return mIsShortFrames;
+    }
+
+    /**
      * Status for each tuning Physical Layer Pipes.
      */
     public static class Atsc3PlpTuningInfo {
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 758f015..2541750 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -156,6 +156,7 @@
 using ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval;
 using ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode;
 using ::android::hardware::tv::tuner::V1_1::FrontendModulation;
+using ::android::hardware::tv::tuner::V1_1::FrontendRollOff;
 using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
 using ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
 using ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
@@ -639,10 +640,12 @@
         jlong firstMbInSlice = (eventsExt.size() > i)
                 ? static_cast<jint>(eventsExt[i].mmtpRecord().firstMbInSlice)
                 : static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
+        jlong tsIndexMask = (eventsExt.size() > i)
+                ? static_cast<jint>(eventsExt[i].mmtpRecord().tsIndexMask) : 0;
 
         jobject obj =
                 env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
-                        mpuSequenceNumber, pts, firstMbInSlice);
+                        mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask);
         env->SetObjectArrayElement(arr, i, obj);
     }
     return arr;
@@ -1242,10 +1245,10 @@
 
 jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
     jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities");
-    jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(III)V");
+    jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V");
 
     jint modulationCap = caps.dvbcCaps().modulationCap;
-    jint fecCap = caps.dvbcCaps().fecCap;
+    jlong fecCap = caps.dvbcCaps().fecCap;
     jint annexCap = caps.dvbcCaps().annexCap;
 
     return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap);
@@ -2484,6 +2487,55 @@
                 env->SetObjectField(statusObj, field, valObj);
                 break;
             }
+            case FrontendStatusExt1_1::hidl_discriminator::rollOff: {
+                jfieldID field = env->GetFieldID(clazz, "mRollOff", "Ljava/lang/Integer;");
+                auto rollOff = s.rollOff();
+                jint intRollOff;
+                bool valid = true;
+                switch(rollOff.getDiscriminator()) {
+                    case FrontendRollOff::hidl_discriminator::dvbs: {
+                        intRollOff = static_cast<jint>(rollOff.dvbs());
+                        break;
+                    }
+                    case FrontendRollOff::hidl_discriminator::isdbs: {
+                        intRollOff = static_cast<jint>(rollOff.isdbs());
+                        break;
+                    }
+                    case FrontendRollOff::hidl_discriminator::isdbs3: {
+                        intRollOff = static_cast<jint>(rollOff.isdbs3());
+                        break;
+                    }
+                    default:
+                        valid = false;
+                        break;
+                }
+                if (valid) {
+                    jobject newIntegerObj = env->NewObject(intClazz, initInt, intRollOff);
+                    env->SetObjectField(statusObj, field, newIntegerObj);
+                }
+                break;
+            }
+            case FrontendStatusExt1_1::hidl_discriminator::isMiso: {
+                jfieldID field = env->GetFieldID(clazz, "mIsMisoEnabled", "Ljava/lang/Boolean;");
+                jobject newBooleanObj = env->NewObject(
+                        booleanClazz, initBoolean, static_cast<jboolean>(s.isMiso()));
+                env->SetObjectField(statusObj, field, newBooleanObj);
+                break;
+            }
+            case FrontendStatusExt1_1::hidl_discriminator::isLinear: {
+                jfieldID field = env->GetFieldID(clazz, "mIsLinear", "Ljava/lang/Boolean;");
+                jobject newBooleanObj = env->NewObject(
+                        booleanClazz, initBoolean, static_cast<jboolean>(s.isLinear()));
+                env->SetObjectField(statusObj, field, newBooleanObj);
+                break;
+            }
+            case FrontendStatusExt1_1::hidl_discriminator::isShortFrames: {
+                jfieldID field = env->GetFieldID(clazz, "mIsShortFrames", "Ljava/lang/Boolean;");
+                jobject newBooleanObj = env->NewObject(
+                        booleanClazz, initBoolean, static_cast<jboolean>(s.isShortFrames()));
+                env->SetObjectField(statusObj, field, newBooleanObj);
+                break;
+            }
             default: {
                 break;
             }
@@ -2494,7 +2546,7 @@
 
 bool JTuner::isV1_1ExtendedStatusType(int type) {
     return (type > static_cast<int>(FrontendStatusType::ATSC3_PLP_INFO)
-                && type <= static_cast<int>(FrontendStatusTypeExt1_1::TS_DATA_RATES));
+                && type <= static_cast<int>(FrontendStatusTypeExt1_1::IS_SHORT_FRAMES));
 }
 
 jint JTuner::closeFrontend() {
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 02e1ebe..7793d6c 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -46,6 +46,7 @@
         "native_window_jni.cpp",
         "net.c",
         "obb.cpp",
+        "permission_manager.cpp",
         "sensor.cpp",
         "sharedmem.cpp",
         "storage_manager.cpp",
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
new file mode 100644
index 0000000..6a5d2c0
--- /dev/null
+++ b/native/android/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+  "presubmit": [
+    {
+       "name": "CtsPermissionManagerNativeTestCases",
+       "file_patterns": ["permission_manager.cpp"]
+    },
+    {
+       "name": "CtsPermissionTestCases",
+       "options": [
+           {
+              "include-filter": "android.permission.cts.PermissionManagerNativeJniTest"
+           }
+       ],
+       "file_patterns": ["permission_manager.cpp"]
+    }
+  ]
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 0414930..3027eac 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -176,6 +176,7 @@
     AObbInfo_getPackageName;
     AObbInfo_getVersion;
     AObbScanner_getObbInfo;
+    APermissionManager_checkPermission; # introduced=31
     ASensorEventQueue_disableSensor;
     ASensorEventQueue_enableSensor;
     ASensorEventQueue_getEvents;
diff --git a/native/android/permission_manager.cpp b/native/android/permission_manager.cpp
new file mode 100644
index 0000000..166e00e
--- /dev/null
+++ b/native/android/permission_manager.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#include <android/permission_manager.h>
+#include <binder/ActivityManager.h>
+
+namespace android {
+namespace permissionmananger {
+
+// Global instance of ActivityManager, service is obtained only on first use.
+static ActivityManager gAm;
+
+} // permissionmanager
+} // android
+
+using namespace android;
+using namespace permissionmananger;
+
+int32_t APermissionManager_checkPermission(const char* permission,
+                                           pid_t pid,
+                                           uid_t uid,
+                                           int32_t* outResult) {
+    status_t result = gAm.checkPermission(String16(permission), pid, uid, outResult);
+    if (result == DEAD_OBJECT) {
+        return PERMISSION_MANAGER_STATUS_SERVICE_UNAVAILABLE;
+    } else if (result != NO_ERROR) {
+        return PERMISSION_MANAGER_STATUS_ERROR_UNKNOWN;
+    }
+    return PERMISSION_MANAGER_STATUS_OK;
+}
diff --git a/packages/CarSystemUI/res/values-af/strings_car.xml b/packages/CarSystemUI/res/values-af/strings_car.xml
deleted file mode 100644
index a6b6093..0000000
--- a/packages/CarSystemUI/res/values-af/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gas"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gas"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Voeg gebruiker by"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nuwe gebruiker"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Enige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-am/strings_car.xml b/packages/CarSystemUI/res/values-am/strings_car.xml
deleted file mode 100644
index 7f5895a..0000000
--- a/packages/CarSystemUI/res/values-am/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"እንግዳ"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"እንግዳ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ተጠቃሚ አክል"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"አዲስ ተጠቃሚ"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሳቸውን ቦታ ማቀናበር አለባቸው።"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ማዘመን ይችላል።"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-as/strings_car.xml b/packages/CarSystemUI/res/values-as/strings_car.xml
deleted file mode 100644
index 6eabbd4..0000000
--- a/packages/CarSystemUI/res/values-as/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"অতিথি"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"অতিথি"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"নতুন ব্যৱহাৰকাৰী"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰীক যোগ কৰে, তেতিয়া তেওঁ নিজৰ ঠাই ছেট আপ কৰাটো প্ৰয়োজন হয়।"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"অন্য সকলো ব্যৱহাৰকাৰীৰ বাবে যিকোনো এজন ব্যৱহাৰকাৰীয়ে এপ্‌সমূহ আপডে\'ট কৰিব পাৰে।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-az/strings_car.xml b/packages/CarSystemUI/res/values-az/strings_car.xml
deleted file mode 100644
index aeee105..0000000
--- a/packages/CarSystemUI/res/values-az/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Qonaq"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Qonaq"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"İstifadəçi əlavə edin"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Yeni istifadəçi"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Yeni istifadəçi əlavə etdiyinizdə həmin şəxs öz yerini təyin etməlidir."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"İstənilən istifadəçi digər bütün istifadəçilər üçün tətbiqləri güncəlləyə bilər."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml b/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml
deleted file mode 100644
index f3b53a5..0000000
--- a/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Dodaj korisnika"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-be/strings_car.xml b/packages/CarSystemUI/res/values-be/strings_car.xml
deleted file mode 100644
index 1215af2..0000000
--- a/packages/CarSystemUI/res/values-be/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Госць"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Госць"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Дадаць карыстальніка"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Новы карыстальнік"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Калі вы дадаяце новага карыстальніка, яму трэба наладзіць свой профіль."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Кожны карыстальнік прылады можа абнаўляць праграмы для ўсіх іншых карыстальнікаў."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bg/strings_car.xml b/packages/CarSystemUI/res/values-bg/strings_car.xml
deleted file mode 100644
index d95b18e..0000000
--- a/packages/CarSystemUI/res/values-bg/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Гост"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Гост"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Добавяне на потребител"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Нов потребител"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Когато добавите нов потребител, той трябва да настрои работното си пространство."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Всеки потребител може да актуализира приложенията за всички останали потребители."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bn/strings_car.xml b/packages/CarSystemUI/res/values-bn/strings_car.xml
deleted file mode 100644
index f44ba6e..0000000
--- a/packages/CarSystemUI/res/values-bn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"অতিথি"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"অতিথি সেশন শুরু করুন"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ব্যবহারকারী যোগ করুন"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"নতুন ব্যবহারকারী"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"নতুন ব্যবহারকারী যোগ করলে, তার স্পেস তাকে সেট-আপ করে নিতে হবে।"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"যেকোনও ব্যবহারকারী বাকি সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bs/strings_car.xml b/packages/CarSystemUI/res/values-bs/strings_car.xml
deleted file mode 100644
index e56f861..0000000
--- a/packages/CarSystemUI/res/values-bs/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Dodaj korisnika"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može ažurirati aplikacije za sve druge korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ca/strings_car.xml b/packages/CarSystemUI/res/values-ca/strings_car.xml
deleted file mode 100644
index 89725a2..0000000
--- a/packages/CarSystemUI/res/values-ca/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Convidat"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Convidat"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Afegeix un usuari"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Usuari nou"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar el seu espai."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Qualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-cs/strings_car.xml b/packages/CarSystemUI/res/values-cs/strings_car.xml
deleted file mode 100644
index 1043950..0000000
--- a/packages/CarSystemUI/res/values-cs/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Host"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Host"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Přidat uživatele"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nový uživatel"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Každý nově přidaný uživatel si musí nastavit vlastní prostor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Každý uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-da/strings_car.xml b/packages/CarSystemUI/res/values-da/strings_car.xml
deleted file mode 100644
index 7a63ec1..0000000
--- a/packages/CarSystemUI/res/values-da/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gæst"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gæst"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Tilføj bruger"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Ny bruger"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Når du tilføjer en ny bruger, skal vedkommende konfigurere sit område."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Alle brugere kan opdatere apps for alle andre brugere."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-de/strings_car.xml b/packages/CarSystemUI/res/values-de/strings_car.xml
deleted file mode 100644
index c1acc65..0000000
--- a/packages/CarSystemUI/res/values-de/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gast"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gast"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Nutzer hinzufügen"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Neuer Nutzer"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Jeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-el/strings_car.xml b/packages/CarSystemUI/res/values-el/strings_car.xml
deleted file mode 100644
index 48c5c3e..0000000
--- a/packages/CarSystemUI/res/values-el/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Επισκέπτης"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Επισκέπτης"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Προσθήκη χρήστη"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Νέος χρήστης"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Οποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rAU/strings_car.xml b/packages/CarSystemUI/res/values-en-rAU/strings_car.xml
deleted file mode 100644
index 55dc48c..0000000
--- a/packages/CarSystemUI/res/values-en-rAU/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rCA/strings_car.xml b/packages/CarSystemUI/res/values-en-rCA/strings_car.xml
deleted file mode 100644
index 55dc48c..0000000
--- a/packages/CarSystemUI/res/values-en-rCA/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rGB/strings_car.xml b/packages/CarSystemUI/res/values-en-rGB/strings_car.xml
deleted file mode 100644
index 55dc48c..0000000
--- a/packages/CarSystemUI/res/values-en-rGB/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rIN/strings_car.xml b/packages/CarSystemUI/res/values-en-rIN/strings_car.xml
deleted file mode 100644
index 55dc48c..0000000
--- a/packages/CarSystemUI/res/values-en-rIN/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rXC/strings_car.xml b/packages/CarSystemUI/res/values-en-rXC/strings_car.xml
deleted file mode 100644
index 17ad62c..0000000
--- a/packages/CarSystemUI/res/values-en-rXC/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎Guest‎‏‎‎‏‎"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎Guest‎‏‎‎‏‎"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎Add User‎‏‎‎‏‎"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎New User‎‏‎‎‏‎"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎When you add a new user, that person needs to set up their space.‎‏‎‎‏‎"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎Any user can update apps for all other users.‎‏‎‎‏‎"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es-rUS/strings_car.xml b/packages/CarSystemUI/res/values-es-rUS/strings_car.xml
deleted file mode 100644
index cc31ae4..0000000
--- a/packages/CarSystemUI/res/values-es-rUS/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Invitado"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Invitado"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Agregar usuario"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Usuario nuevo"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Cuando agregues un usuario nuevo, esa persona deberá configurar su espacio."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Cualquier usuario podrá actualizar las apps de otras personas."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es/strings_car.xml b/packages/CarSystemUI/res/values-es/strings_car.xml
deleted file mode 100644
index 26ce2f1..0000000
--- a/packages/CarSystemUI/res/values-es/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Invitado"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Invitado"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Añadir usuario"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nuevo usuario"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Al añadir un usuario, esta persona debe configurar su espacio."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Cualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-et/strings_car.xml b/packages/CarSystemUI/res/values-et/strings_car.xml
deleted file mode 100644
index ce475b1..0000000
--- a/packages/CarSystemUI/res/values-et/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Külaline"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Külaline"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Lisa kasutaja"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Uus kasutaja"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Iga kasutaja saab rakendusi värskendada kõigi teiste kasutajate jaoks."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-eu/strings_car.xml b/packages/CarSystemUI/res/values-eu/strings_car.xml
deleted file mode 100644
index be7c6dc..0000000
--- a/packages/CarSystemUI/res/values-eu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gonbidatua"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gonbidatua"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Gehitu erabiltzaile bat"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Erabiltzaile berria"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Erabiltzaile bat gehitzen duzunean, bere eremua konfiguratu beharko du."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Edozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fa/strings_car.xml b/packages/CarSystemUI/res/values-fa/strings_car.xml
deleted file mode 100644
index 5138d5f..0000000
--- a/packages/CarSystemUI/res/values-fa/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"مهمان"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"مهمان"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"افزودن کاربر"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"کاربر جدید"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"وقتی کاربری جدید اضافه می‌کنید، آن فرد باید فضای خود را تنظیم کند."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"هر کاربری می‌تواند برنامه‌ها را برای همه کاربران دیگر به‌روزرسانی کند."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fi/strings_car.xml b/packages/CarSystemUI/res/values-fi/strings_car.xml
deleted file mode 100644
index 5963b52..0000000
--- a/packages/CarSystemUI/res/values-fi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Vieras"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Vieras"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Lisää käyttäjä"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Uusi käyttäjä"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kun lisäät uuden käyttäjän, hänen on valittava oman tilansa asetukset."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Kaikki käyttäjät voivat päivittää muiden käyttäjien sovelluksia."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml b/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml
deleted file mode 100644
index ab0a302..0000000
--- a/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Invité"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Invité"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Ajouter un utilisateur"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nouvel utilisateur"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Tout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr/strings_car.xml b/packages/CarSystemUI/res/values-fr/strings_car.xml
deleted file mode 100644
index b072ecc..0000000
--- a/packages/CarSystemUI/res/values-fr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Invité"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Invité"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Ajouter un utilisateur"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nouvel utilisateur"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"N\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gl/strings_car.xml b/packages/CarSystemUI/res/values-gl/strings_car.xml
deleted file mode 100644
index fc4af28..0000000
--- a/packages/CarSystemUI/res/values-gl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Engadir usuario"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novo usuario"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Cando engadas un usuario novo, este deberá configurar o seu espazo."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Calquera usuario pode actualizar as aplicacións para o resto dos usuarios."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gu/strings_car.xml b/packages/CarSystemUI/res/values-gu/strings_car.xml
deleted file mode 100644
index 48a9daca..0000000
--- a/packages/CarSystemUI/res/values-gu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"અતિથિ"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"અતિથિ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"વપરાશકર્તા ઉમેરો"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"નવા વપરાશકર્તા"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિએ તેમની સ્પેસ સેટ કરવાની જરૂર રહે છે."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"કોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hi/strings_car.xml b/packages/CarSystemUI/res/values-hi/strings_car.xml
deleted file mode 100644
index ec83e95..0000000
--- a/packages/CarSystemUI/res/values-hi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"मेहमान"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"मेहमान"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"उपयोगकर्ता जोड़ें"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"नया उपयोगकर्ता"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तब उसे अपनी जगह सेट करनी होती है."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"कोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hr/strings_car.xml b/packages/CarSystemUI/res/values-hr/strings_car.xml
deleted file mode 100644
index d707145..0000000
--- a/packages/CarSystemUI/res/values-hr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Dodajte korisnika"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može ažurirati aplikacije za ostale korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hu/strings_car.xml b/packages/CarSystemUI/res/values-hu/strings_car.xml
deleted file mode 100644
index 4f11ec2..0000000
--- a/packages/CarSystemUI/res/values-hu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Vendég"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Vendég"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Felhasználó hozzáadása"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Új felhasználó"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját felületét."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Bármely felhasználó frissítheti az alkalmazásokat az összes felhasználó számára."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hy/strings_car.xml b/packages/CarSystemUI/res/values-hy/strings_car.xml
deleted file mode 100644
index 5559999..0000000
--- a/packages/CarSystemUI/res/values-hy/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Հյուր"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Հյուրի ռեժիմ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Ավելացնել օգտատեր"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Նոր օգտատեր"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Երբ դուք նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը։"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Ցանկացած օգտատեր կարող է թարմացնել հավելվածները բոլոր մյուս հաշիվների համար։"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-in/strings_car.xml b/packages/CarSystemUI/res/values-in/strings_car.xml
deleted file mode 100644
index 69f23ce..0000000
--- a/packages/CarSystemUI/res/values-in/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Tamu"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Tamu"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Tambahkan Pengguna"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Pengguna Baru"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Setiap pengguna dapat mengupdate aplikasi untuk semua pengguna lain."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-is/strings_car.xml b/packages/CarSystemUI/res/values-is/strings_car.xml
deleted file mode 100644
index 430e902..0000000
--- a/packages/CarSystemUI/res/values-is/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gestur"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gestur"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Bæta notanda við"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nýr notandi"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Þegar þú bætir nýjum notanda við þarf viðkomandi að setja upp sitt eigið svæði."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Allir notendur geta uppfært forrit fyrir alla aðra notendur."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-it/strings_car.xml b/packages/CarSystemUI/res/values-it/strings_car.xml
deleted file mode 100644
index 9c498df..0000000
--- a/packages/CarSystemUI/res/values-it/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Ospite"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Ospite"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Aggiungi utente"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nuovo utente"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Il nuovo utente, una volta aggiunto, dovrà configurare il suo spazio."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Qualsiasi utente può aggiornare le app per tutti gli altri."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ja/strings_car.xml b/packages/CarSystemUI/res/values-ja/strings_car.xml
deleted file mode 100644
index d59b267..0000000
--- a/packages/CarSystemUI/res/values-ja/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ゲスト"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ゲスト"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ユーザーを追加"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"新しいユーザー"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"どのユーザーも他のすべてのユーザーに代わってアプリを更新できます。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ka/strings_car.xml b/packages/CarSystemUI/res/values-ka/strings_car.xml
deleted file mode 100644
index cb0e8fd..0000000
--- a/packages/CarSystemUI/res/values-ka/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"სტუმარი"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"სტუმარი"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"მომხმარებლის დამატება"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"ახალი მომხმარებელი"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-km/strings_car.xml b/packages/CarSystemUI/res/values-km/strings_car.xml
deleted file mode 100644
index b6a9864..0000000
--- a/packages/CarSystemUI/res/values-km/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ភ្ញៀវ"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ភ្ញៀវ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"បញ្ចូល​អ្នក​ប្រើប្រាស់"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"អ្នក​ប្រើប្រាស់​ថ្មី"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"នៅពេលដែល​អ្នកបញ្ចូល​អ្នក​ប្រើប្រាស់ថ្មី បុគ្គល​នោះ​ត្រូវរៀបចំ​ទំហំផ្ទុក​របស់គេ។"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"អ្នកប្រើប្រាស់​ណាក៏​អាច​ដំឡើងកំណែ​កម្មវិធី​សម្រាប់​អ្នកប្រើប្រាស់ទាំងអស់​ផ្សេងទៀត​បានដែរ។"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-kn/strings_car.xml b/packages/CarSystemUI/res/values-kn/strings_car.xml
deleted file mode 100644
index 23e5415..0000000
--- a/packages/CarSystemUI/res/values-kn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ಅತಿಥಿ"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ಅತಿಥಿ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"ಹೊಸ ಬಳಕೆದಾರ"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"ನೀವು ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ko/strings_car.xml b/packages/CarSystemUI/res/values-ko/strings_car.xml
deleted file mode 100644
index 3997c0f..0000000
--- a/packages/CarSystemUI/res/values-ko/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"게스트"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"게스트"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"사용자 추가"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"신규 사용자"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"추가된 신규 사용자는 자신만의 공간을 설정해야 합니다."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"누구나 다른 모든 사용자를 위해 앱을 업데이트할 수 있습니다."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lt/strings_car.xml b/packages/CarSystemUI/res/values-lt/strings_car.xml
deleted file mode 100644
index a8cf0a7..0000000
--- a/packages/CarSystemUI/res/values-lt/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Svečias"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Svečias"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Pridėti naudotoją"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Naujas naudotojas"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo vietą."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Bet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lv/strings_car.xml b/packages/CarSystemUI/res/values-lv/strings_car.xml
deleted file mode 100644
index 3b7f386..0000000
--- a/packages/CarSystemUI/res/values-lv/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Viesis"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Viesis"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Pievienot lietotāju"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Jauns lietotājs"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kad pievienojat jaunu lietotāju, viņam ir jāizveido savs profils."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Ikviens lietotājs var atjaunināt lietotnes visu lietotāju vārdā."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mk/strings_car.xml b/packages/CarSystemUI/res/values-mk/strings_car.xml
deleted file mode 100644
index c1941467..0000000
--- a/packages/CarSystemUI/res/values-mk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Гостин"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Гостин"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Додај корисник"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Нов корисник"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Кога додавате нов корисник, тоа лице треба да го постави својот простор."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Секој корисник може да ажурира апликации за сите други корисници."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ml/strings_car.xml b/packages/CarSystemUI/res/values-ml/strings_car.xml
deleted file mode 100644
index 3ce44f7..0000000
--- a/packages/CarSystemUI/res/values-ml/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"അതിഥി"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"അതിഥി"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ഉപയോക്താവിനെ ചേർക്കുക"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"പുതിയ ഉപയോക്താവ്"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"നിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തി സ്വന്തം ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"മറ്റെല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്‌ഡേറ്റ് ചെയ്യാൻ ഏതൊരു ഉപയോക്താവിനും കഴിയും."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mn/strings_car.xml b/packages/CarSystemUI/res/values-mn/strings_car.xml
deleted file mode 100644
index 9628f7b..0000000
--- a/packages/CarSystemUI/res/values-mn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Зочин"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Зочин"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Хэрэглэгч нэмэх"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Шинэ хэрэглэгч"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Та шинэ хэрэглэгчийг нэмэх үед тухайн хэрэглэгч хувийн орон зайгаа тохируулах шаардлагатай."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Дурын хэрэглэгч бусад бүх хэрэглэгчийн аппуудыг шинэчлэх боломжтой."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mr/strings_car.xml b/packages/CarSystemUI/res/values-mr/strings_car.xml
deleted file mode 100644
index cf2ad5e..0000000
--- a/packages/CarSystemUI/res/values-mr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"अतिथी"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"अतिथी"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"वापरकर्ता जोडा"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"नवीन वापरकर्ता"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"तुम्ही नवीन वापरकर्ता जोडल्यावर, त्या व्यक्तीने त्यांची जागा सेट करणे आवश्यक असते."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"कोणत्याही वापरकर्त्याला इतर सर्व वापरकर्त्यांसाठी अ‍ॅप्स अपडेट करता येतात."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ms/strings_car.xml b/packages/CarSystemUI/res/values-ms/strings_car.xml
deleted file mode 100644
index e846b62..0000000
--- a/packages/CarSystemUI/res/values-ms/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Tetamu"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Tetamu"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Tambah Pengguna"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Pengguna Baharu"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Apabila anda menambahkan pengguna baharu, orang itu perlu menyediakan ruang mereka."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Mana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-my/strings_car.xml b/packages/CarSystemUI/res/values-my/strings_car.xml
deleted file mode 100644
index e5e67d1..0000000
--- a/packages/CarSystemUI/res/values-my/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ဧည့်သည်"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ဧည့်သည်"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"အသုံးပြုသူ ထည့်ရန်"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"အသုံးပြုသူ အသစ်"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"အသုံးပြုသူအသစ် ထည့်သည့်အခါ ထိုသူသည် မိမိ၏ နေရာကို စနစ်ထည့်သွင်းရပါမည်။"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"အခြားအသုံးပြုသူ အားလုံးအတွက် အက်ပ်များကို မည်သူမဆို အပ်ဒိတ်လုပ်နိုင်သည်။"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nb/strings_car.xml b/packages/CarSystemUI/res/values-nb/strings_car.xml
deleted file mode 100644
index 2c10092..0000000
--- a/packages/CarSystemUI/res/values-nb/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gjest"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gjest"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Legg til en bruker"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Ny bruker"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Alle brukere kan oppdatere apper for alle andre brukere."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nl/strings_car.xml b/packages/CarSystemUI/res/values-nl/strings_car.xml
deleted file mode 100644
index 8f008a6..0000000
--- a/packages/CarSystemUI/res/values-nl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gast"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gast"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Gebruiker toevoegen"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nieuwe gebruiker"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Als je een nieuwe gebruiker toevoegt, moet die persoon een eigen profiel instellen."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Elke gebruiker kan apps updaten voor alle andere gebruikers"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pa/strings_car.xml b/packages/CarSystemUI/res/values-pa/strings_car.xml
deleted file mode 100644
index a15a6a5..0000000
--- a/packages/CarSystemUI/res/values-pa/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ਮਹਿਮਾਨ"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ਮਹਿਮਾਨ"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pl/strings_car.xml b/packages/CarSystemUI/res/values-pl/strings_car.xml
deleted file mode 100644
index 0c48dcf..0000000
--- a/packages/CarSystemUI/res/values-pl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gość"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gość"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Dodaj użytkownika"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nowy użytkownik"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Każdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml b/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml
deleted file mode 100644
index 640e535..0000000
--- a/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Adicionar utilizador"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novo utilizador"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Qualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt/strings_car.xml b/packages/CarSystemUI/res/values-pt/strings_car.xml
deleted file mode 100644
index 6b53b5b..0000000
--- a/packages/CarSystemUI/res/values-pt/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Adicionar usuário"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Novo usuário"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Quando você adiciona um usuário novo, essa pessoa precisa configurar o espaço dela."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Qualquer usuário pode atualizar apps para os demais usuários."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ro/strings_car.xml b/packages/CarSystemUI/res/values-ro/strings_car.xml
deleted file mode 100644
index 7f4fe7a..0000000
--- a/packages/CarSystemUI/res/values-ro/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Invitat"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Invitat"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Adăugați un utilizator"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Utilizator nou"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Orice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ru/strings_car.xml b/packages/CarSystemUI/res/values-ru/strings_car.xml
deleted file mode 100644
index 99819dd..0000000
--- a/packages/CarSystemUI/res/values-ru/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Гость"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Гость"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Добавить пользователя"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Новый пользователь"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Когда вы добавите пользователя, ему потребуется настроить профиль."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Любой пользователь устройства может обновлять приложения для всех аккаунтов."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-si/strings_car.xml b/packages/CarSystemUI/res/values-si/strings_car.xml
deleted file mode 100644
index 6444e91f..0000000
--- a/packages/CarSystemUI/res/values-si/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"අමුත්තා"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"අමුත්තා"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"පරිශීලක එක් කරන්න"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"නව පරිශීලක"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"ඔබ අලුත් පරිශීලකයෙක් එක් කරන විට, එම පුද්ගලයාට තමන්ගේ ඉඩ සකසා ගැනීමට අවශ්‍ය වේ."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"සියලුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යෙදුම් යාවත්කාලීන කළ හැක."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sk/strings_car.xml b/packages/CarSystemUI/res/values-sk/strings_car.xml
deleted file mode 100644
index c058a32..0000000
--- a/packages/CarSystemUI/res/values-sk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Hosť"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Hosť"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Pridať používateľa"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nový používateľ"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Akýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sl/strings_car.xml b/packages/CarSystemUI/res/values-sl/strings_car.xml
deleted file mode 100644
index b8324e0..0000000
--- a/packages/CarSystemUI/res/values-sl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Dodaj uporabnika"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Nov uporabnik"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Vsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sq/strings_car.xml b/packages/CarSystemUI/res/values-sq/strings_car.xml
deleted file mode 100644
index 7e676ba..0000000
--- a/packages/CarSystemUI/res/values-sq/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"I ftuar"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"I ftuar"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Shto përdorues"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Përdorues i ri"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Çdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sr/strings_car.xml b/packages/CarSystemUI/res/values-sr/strings_car.xml
deleted file mode 100644
index 4d23fdb..0000000
--- a/packages/CarSystemUI/res/values-sr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Гост"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Гост"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Додај корисника"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Нови корисник"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Када додате новог корисника, та особа треба да подеси свој простор."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Сваки корисник може да ажурира апликације за све остале кориснике."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sv/strings_car.xml b/packages/CarSystemUI/res/values-sv/strings_car.xml
deleted file mode 100644
index 36fcdaa..0000000
--- a/packages/CarSystemUI/res/values-sv/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Gäst"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Gäst"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Lägg till användare"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Ny användare"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Alla användare kan uppdatera appar för andra användare."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sw/strings_car.xml b/packages/CarSystemUI/res/values-sw/strings_car.xml
deleted file mode 100644
index 75573d7..0000000
--- a/packages/CarSystemUI/res/values-sw/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Mgeni"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Mgeni"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Weka Mtumiaji"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Mtumiaji Mpya"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Ukiongeza mtumiaji mpya, ni lazima aweke kikundi chake."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Mtumiaji yeyote anaweza kusasisha programu za watumiaji wengine wote."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-te/strings_car.xml b/packages/CarSystemUI/res/values-te/strings_car.xml
deleted file mode 100644
index 7f0d090..0000000
--- a/packages/CarSystemUI/res/values-te/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"గెస్ట్"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"గెస్ట్"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"యూజర్‌ను జోడించండి"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"కొత్త యూజర్"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"మీరు కొత్త యూజర్‌ను జోడించినప్పుడు, ఆ వ్యక్తి తన ప్రదేశాన్ని సెటప్ చేసుకోవాలి."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ఏ యూజర్ అయినా మిగతా అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-th/strings_car.xml b/packages/CarSystemUI/res/values-th/strings_car.xml
deleted file mode 100644
index 8e47499..0000000
--- a/packages/CarSystemUI/res/values-th/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"ผู้ใช้ชั่วคราว"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"ผู้ใช้ชั่วคราว"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"เพิ่มผู้ใช้"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"ผู้ใช้ใหม่"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"ผู้ใช้ทุกคนจะอัปเดตแอปให้ผู้ใช้คนอื่นๆ ได้"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tl/strings_car.xml b/packages/CarSystemUI/res/values-tl/strings_car.xml
deleted file mode 100644
index b8a44e6..0000000
--- a/packages/CarSystemUI/res/values-tl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Bisita"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Bisita"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Magdagdag ng User"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Bagong User"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Puwedeng i-update ng sinumang user ang mga app para sa lahat ng iba pang user."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tr/strings_car.xml b/packages/CarSystemUI/res/values-tr/strings_car.xml
deleted file mode 100644
index c59aff8..0000000
--- a/packages/CarSystemUI/res/values-tr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Misafir"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Misafir"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Kullanıcı Ekle"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Yeni Kullanıcı"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Yeni kullanıcı eklediğinizde, bu kişinin alanını ayarlaması gerekir."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Herhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uk/strings_car.xml b/packages/CarSystemUI/res/values-uk/strings_car.xml
deleted file mode 100644
index b1aee0d..0000000
--- a/packages/CarSystemUI/res/values-uk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Гість"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Гість"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Додати користувача"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Новий користувач"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Коли ви додаєте нового користувача, він має налаштувати свій профіль."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Будь-який користувач може оновлювати додатки для решти людей."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uz/strings_car.xml b/packages/CarSystemUI/res/values-uz/strings_car.xml
deleted file mode 100644
index eb4712c..0000000
--- a/packages/CarSystemUI/res/values-uz/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Mehmon"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Mehmon"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Foydalanuvchi kiritish"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Yangi foydalanuvchi"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Yangi profil kiritilgach, uni sozlash lozim."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Qurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-vi/strings_car.xml b/packages/CarSystemUI/res/values-vi/strings_car.xml
deleted file mode 100644
index 452257a..0000000
--- a/packages/CarSystemUI/res/values-vi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Khách"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Bắt đầu phiên khách"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Thêm người dùng"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Người dùng mới"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Khi bạn thêm một người dùng mới, họ cần thiết lập không gian của mình."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Bất kỳ người dùng nào cũng có thể cập nhật ứng dụng cho tất cả những người dùng khác."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml b/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml
deleted file mode 100644
index d8aea67..0000000
--- a/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"访客"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"访客"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"添加用户"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"新用户"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"当您添加新用户后,该用户需要自行设置个人空间。"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"任何用户都可以为所有其他用户更新应用。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml b/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml
deleted file mode 100644
index 1970ec9..0000000
--- a/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"訪客"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"訪客"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"新增使用者"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"新使用者"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"你新增的使用者必須自行設定個人空間。"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"任何使用者皆可為所有其他使用者更新應用程式。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml b/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml
deleted file mode 100644
index 1970ec9..0000000
--- a/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"訪客"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"訪客"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"新增使用者"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"新使用者"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"你新增的使用者必須自行設定個人空間。"</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"任何使用者皆可為所有其他使用者更新應用程式。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zu/strings_car.xml b/packages/CarSystemUI/res/values-zu/strings_car.xml
deleted file mode 100644
index 1f8227d..0000000
--- a/packages/CarSystemUI/res/values-zu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="car_guest" msgid="1125545940563459016">"Isihambeli"</string>
-    <string name="start_guest_session" msgid="548879769864070364">"Isihambeli"</string>
-    <string name="car_add_user" msgid="9196649698797257695">"Engeza umsebenzisi"</string>
-    <string name="car_new_user" msgid="2994965724661108420">"Umsebenzisi omusha"</string>
-    <string name="user_add_user_message_setup" msgid="116571509380700718">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha izikhala zakhe."</string>
-    <string name="user_add_user_message_update" msgid="537998123816022363">"Noma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza zabanye abasebenzisi."</string>
-</resources>
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
index a492e47..4ae6ea6 100644
--- a/packages/CarrierDefaultApp/res/values-hu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -8,7 +8,7 @@
     <string name="portal_notification_detail" msgid="2295729385924660881">"Koppintson a(z) %s webhely meglátogatásához"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Vegye fel a kapcsolatot szolgáltatójával (%s)"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nincs mobiladat-kapcsolat"</string>
-    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy roamingcsomagot a következőn keresztül: %s"</string>
+    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy barangolási csomagot a következőn keresztül: %s"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobiladat-állapot"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Bejelentkezés a mobilhálózatra"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-af/strings.xml b/packages/DynamicSystemInstallationService/res/values-af/strings.xml
index c5f21cb..231a5ce 100644
--- a/packages/DynamicSystemInstallationService/res/values-af/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-af/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamiese stelsel is gereed. Herbegin jou toestel om dit te begin gebruik."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Installeer tans"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Kon nie installeer nie"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kon nie prent bekragtig nie. Staak installering."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kon nie beeldafskrif bekragtig nie. Staak installering."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Laat loop tans \'n dinamiese stelsel. Herbegin om die oorspronklike Android-weergawe te gebruik."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Kanselleer"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Gooi weg"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-az/strings.xml b/packages/DynamicSystemInstallationService/res/values-az/strings.xml
index 159794e..03d7cca 100644
--- a/packages/DynamicSystemInstallationService/res/values-az/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-az/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamik sistem hazırdır. İstifadəyə başlamaq üçün cihazınızı yenidən başladın."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Quraşdırılır"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Quraşdırılmadı"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Şəkil təsdiqlənmədi. Quraşdırmanı dayandırın."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Görüntü doğrulanması alınmadı. Quraşdırmanı dayandırın."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Hazırda dinamik sistem icra olunur. Orijinal Android versiyasından istifadə etmək üçün yenidən başladın."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Ləğv edin"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"İmtina edin"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
index f44dd74..87d0158 100644
--- a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"ডায়নামিক সিস্টেম রেডি হয়ে গেছে। সেটি ব্যবহার করা শুরু করতে আপনার ডিভাইস রিস্টার্ট করুন।"</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"ইনস্টল করা হচ্ছে"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"ইনস্টল করা যায়নি"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"ছবি যাচাই করা যায়নি। ইনস্টলেশন বন্ধ করুন।"</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"ইমেজ যাচাই করা যায়নি। ইনস্টলেশন বন্ধ করুন।"</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"বর্তমানে ডায়নামিক সিস্টেম চালানো হচ্ছে। আসল Android ভার্সন ব্যবহার করার জন্য রিস্টার্ট করুন।"</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"বাতিল করুন"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"বাতিল করুন"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
index 9eb2ec7..7798424 100644
--- a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamični sistem je spreman. Da ga počnete koristiti, ponovo pokrenite uređaj."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Instaliranje je u toku"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Instaliranje nije uspjelo"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Potvrda slike sistema nije uspjela. Prekini instalaciju."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Potvrda slike diska nije uspjela. Prekini instalaciju."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Dinamični sistem je sada aktivan. Ponovo pokrenite da koristite originalnu verziju Androida."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Otkaži"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Odbaci"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
index b8a7f37..41e0bbe 100644
--- a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynamický systém je připraven. Chcete-li ho začít používat, restartujte zařízení."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Probíhá instalace"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Instalace se nezdařila"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz se nepodařilo ověřit. Zrušte instalaci."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz disku se nepodařilo ověřit. Zrušte instalaci."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Je spuštěn dynamický systém. Chcete-li použít původní verzi systému Android, restartujte zařízení."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Zrušit"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Zahodit"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
index 9c97687..9976d56 100644
--- a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"سیستم پویا آماده است. برای استفاده از آن، دستگاه را بازراه‌اندازی کنید."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"درحال نصب"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"نصب نشد"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"راستی‌آزمایی تصویر انجام نشد. نصب را لغو کنید."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"اعتبارسنجی نسخه دیسک انجام نشد. نصب را لغو کنید."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"‏درحال‌حاضر سیستم پویا اجرا می‌شود. برای استفاده از نسخه اصلی Android، بازراه‌اندازی کنید."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"لغو کردن"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"صرف‌نظر کردن"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
index 4cfac02..f32fc37 100644
--- a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynaaminen järjestelmä on valmis. Aloita sen käyttö käynnistämällä laite uudelleen."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Asennus käynnissä"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Asennus epäonnistui"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kuvavahvistus epäonnistui. Keskeytä asennus."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Levykuvan vahvistus epäonnistui. Keskeytä asennus."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Käyttää tällä hetkellä dynaamista järjestelmää. Käynnistä uudelleen käyttääksesi alkuperäistä Android-versiota."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Peruuta"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Hylkää"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
index f4b7f73..1df6a81 100644
--- a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamični sustav je spreman. Da biste ga počeli upotrebljavati, ponovno pokrenite svoj uređaj."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Instalacija u tijeku"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Instaliranje nije uspjelo"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Provjera slike nije uspjela. Prekini instalaciju."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Provjera slike diska nije uspjela. Prekini instalaciju."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Trenutačno je pokrenut dinamični sustav. Ponovno pokrenite kako biste upotrebljavali izvornu verziju Androida."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Otkaži"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Odbaci"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
index b155fe2..2540ce6 100644
--- a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"A dinamikus rendszer készen áll. A használatához indítsa újra az eszközt."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Telepítés…"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Sikertelen telepítés"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"A kép ellenőrzése nem sikerült. A telepítés megszakad."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"A lemezkép ellenőrzése nem sikerült. A telepítés megszakad."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Jelenleg dinamikus rendszert futtat. Az eredeti Android-verzió használatához indítsa újra az eszközt."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Mégse"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Elvetés"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
index 287ea91..e85a291 100644
--- a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Դինամիկ համակարգը պատրաստ է։ Այն օգտագործելու համար վերագործարկեք ձեր սարքը։"</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Տեղադրում"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Չհաջողվեց տեղադրել"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Չհաջողվեց հաստատել պատկերը։ Չեղարկել տեղադրումը։"</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Չհաջողվեց հաստատել սկավառակի պատկերը։ Չեղարկեք տեղադրումը։"</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Աշխատեցվում է դինամիկ համակարգը։ Վերագործարկեք՝ Android-ի նախկին տարբերակին անցնելու համար։"</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Չեղարկել"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Հրաժարվել"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-is/strings.xml b/packages/DynamicSystemInstallationService/res/values-is/strings.xml
index e0a415b..4499c14 100644
--- a/packages/DynamicSystemInstallationService/res/values-is/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-is/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Breytilegt kerfi er tilbúið. Endurræstu tækið til að byrja að nota það."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Uppsetning stendur yfir"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Uppsetning mistókst"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ekki tókst að staðfesta mynd. Hættu við uppsetninguna."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ekki tókst að staðfesta diskmynd. Hættu við uppsetninguna."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Tækið keyrir á breytilegu kerfi. Endurræstu til að nota upprunalega Android útgáfu."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Hætta við"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Fleygja"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
index 6aea2f9..3cc1932 100644
--- a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"დინამიური სისტემა მზადაა. გადატვირთეთ მოწყობილობა მის გამოსაყენებლად."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"ინსტალირდება"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"ინსტალაცია ვერ მოხერხდა"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"სურათის ვალიდაცია ვერ მოხერხდა. ინსტალაციის შეწყვეტა."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"იმიჯის ვალიდაცია ვერ მოხერხდა. ინსტალაციის შეწყვეტა."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ამჟამად გამოიყენება დინამიური სისტემა. გადატვირთეთ Android-ის ორიგინალი ვერსიის გამოსაყენებლად."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"გაუქმება"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"გაუქმება"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-km/strings.xml b/packages/DynamicSystemInstallationService/res/values-km/strings.xml
index 510d526..502ae93 100644
--- a/packages/DynamicSystemInstallationService/res/values-km/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-km/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"ប្រព័ន្ធឌីណាមិច​អាចប្រើ​បានហើយ។ ដើម្បីចាប់ផ្ដើមប្រើ​ប្រព័ន្ធឌីណាមិច សូមចាប់ផ្ដើម​ឧបករណ៍របស់អ្នក​ឡើងវិញ។"</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"ការដំឡើងកំពុង​ដំណើរការ"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"ការដំឡើង​មិនបានសម្រេច"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"បញ្ជាក់​ភាពត្រឹមត្រូវ​នៃរូបភាព​មិនបានសម្រេច។ បោះបង់​ការដំឡើង។"</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"ការផ្ទៀងផ្ទាត់ច្បាប់ចម្លងថាស​មិនបានសម្រេច។ បោះបង់​ការដំឡើង។"</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"បច្ចុប្បន្ន​កំពុងដំណើរការ​ប្រព័ន្ធឌីណាមិច។ ចាប់ផ្ដើម​ឡើងវិញ ដើម្បីប្រើ​កំណែ Android ដើម។"</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"បោះបង់"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"លុបចោល"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
index dffe22d..cd5044d 100644
--- a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ಸಿದ್ದವಾಗಿದೆ. ಇದನ್ನು ಬಳಸಲು, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"ಇನ್‌ಸ್ಟಾಲ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"ಚಿತ್ರದ ಮೌಲ್ಯೀಕರಣ ವಿಫಲವಾಗಿದೆ. ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿ."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"ಇಮೇಜ್ ಮೌಲ್ಯೀಕರಣ ವಿಫಲವಾಗಿದೆ. ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿ."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ಪ್ರಸ್ತುತವಾಗಿ ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ರನ್ ಆಗುತ್ತಿದೆ ಮೂಲ Android ಆವೃತ್ತಿ ಬಳಸಲು, ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"ರದ್ದುಗೊಳಿಸಿ"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"ತ್ಯಜಿಸಿ"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
index 79734b7..320faff 100644
--- a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Динамикалык система даяр. Аны колдонуу үчүн, түзмөктү өчүрүп күйгүзүңүз."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Орнотулууда"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Орнотулбай койду"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Сүрөт текшерилбей калды. Орнотууну токтотуңуз."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Дисктин сүрөтү текшерилбей калды. Орнотууну токтотуңуз."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Учурда динамикалык система колдонулууда. Android\'дин түпнуска версиясын колдонуу үчүн, өчүрүп күйгүзүңүз."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Жок"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Жоюу"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
index 5673e8f..2352c22 100644
--- a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinaminė sistema paruošta. Jei norite pradėti ją naudoti, paleiskite įrenginį iš naujo."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Diegiama"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Įdiegti nepavyko"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nepavyko patvirtinti vaizdo. Nutraukti diegimą."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nepavyko patvirtinti atvaizdžio. Nutraukti diegimą."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Šiuo metu paleista dinaminė sistema. Paleiskite iš naujo, jei norite naudoti pradinę „Android“ versiją."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Atšaukti"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Atmesti"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
index 8742d2d..e205b73 100644
--- a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Динамичниот систем е подготвен. За да започнете со користење, рестартирајте го уредот."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Инсталирањето е во тек"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Неуспешно инсталирање"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Проверката на сликата не успеа. Прекини ја инсталацијата."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Проверката на сликата на дискот не успеа. Прекини ја инсталацијата."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Во моментов се извршува динамичен систем. Рестартирајте за да ја користите оригиналната верзија на Android."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Откажи"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Отфрли"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
index e84329b..7afbfd9 100644
--- a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynamic System तयार छ। यसको प्रयोग सुरु गर्न आफ्नो यन्त्र रिस्टार्ट गर्नुहोस्।"</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"इन्स्टल हुँदै छ"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"स्थापना गर्न सकिएन"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"छवि पुष्टि गर्न सकिएन। स्थापना गर्ने प्रक्रिया रद्द गर्नुहोस्।"</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"डिस्कको इमेज पुष्टि गर्न सकिएन। स्थापना गर्ने प्रक्रिया रद्द गर्नुहोस्।"</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"हाल Dynamic System चलिरहेको छ। Android को मूल संस्करण प्रयोग गर्न यन्त्र रिस्टार्ट गर्नुहोस्।"</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"रद्द गर्नुहोस्"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"खारेज गर्नुहोस्"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
index 09ae30d..6513a9e 100644
--- a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"O sistema dinâmico está pronto. Para começar a usá-lo, reinicie o dispositivo."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Instalação em andamento"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Falha na instalação"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem. Cancele a instalação."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem do disco. Cancele a instalação."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Um sistema dinâmico está sendo executado no momento. Reinicie para usar a versão original do Android."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Cancelar"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Descartar"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
index 09ae30d..6513a9e 100644
--- a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"O sistema dinâmico está pronto. Para começar a usá-lo, reinicie o dispositivo."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Instalação em andamento"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Falha na instalação"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem. Cancele a instalação."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem do disco. Cancele a instalação."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Um sistema dinâmico está sendo executado no momento. Reinicie para usar a versão original do Android."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Cancelar"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Descartar"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-si/strings.xml b/packages/DynamicSystemInstallationService/res/values-si/strings.xml
index e842d80..ab0b977 100644
--- a/packages/DynamicSystemInstallationService/res/values-si/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-si/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"ගතික පද්ධතිය සූදානම්ය. එය භාවිතා කිරීම ආරම්භ කිරීමට, ඔබගේ උපාංගය නැවත ආරම්භ කරන්න."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"ස්ථාපනය කෙරෙමින් පවතී"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"ස්ථාපනය අසාර්ථක විය"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"රූප වලංගු කිරීම අසාර්ථක විය. ස්ථාපනය අවලංගු කරන්න"</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"තැටි රූපය වලංගු කිරීම අසාර්ථක විය. ස්ථාපනය අවලංගු කරන්න"</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"දැනට ගතික පද්ධතියක් ක්‍රියාත්මක කරයි. මුල් Android අනුවාදය භාවිතා කිරීමට නැවත ආරම්භ කරන්න."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"අවලංගු කරන්න"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"ඉවත ලන්න"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
index f2025fc..01d6a73 100644
--- a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynamický systém je k dispozícii. Ak ho chcete začať používať, reštartujte zariadenie."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Prebieha inštalácia"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Nepodarilo sa nainštalovať"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obrázok sa nepodarilo overiť. Prerušte inštaláciu."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz disku sa nepodarilo overiť. Prerušte inštaláciu."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Momentálne je spustený dynamický systém. Ak chcete používať pôvodnú verziu Androidu, reštartujte."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Zrušiť"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Zahodiť"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
index 8a92bd3..2f18edb 100644
--- a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynamic system iko tayari. Ili uanze kuitumia, zima kisha uwashe kifaa chako."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Inasakinisha"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Imeshindwa kusakinisha"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Imeshindwa kuthibitisha picha. Ghairi usakinishaji."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Imeshindwa kuthibitisha nakala. Ghairi usakinishaji."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Inatumia Dynamic System kwa sasa. Zima kisha uwashe ili utumie toleo halisi la Android."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Ghairi"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Ondoa"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
index 1a1f0a0..6726a4a 100644
--- a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dynamic system தயாராக உள்ளது. இதைப் பயன்படுத்தத் தொடங்க உங்கள் சாதனத்தை மீண்டும் தொடங்கவும்."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"நிறுவப்படுகிறது"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"நிறுவ முடியவில்லை"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"படத்தைச் சரிபார்க்க முடியவில்லை. நிறுவலை ரத்துசெய்யவும்."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"டிஸ்க் இமேஜைச் சரிபார்க்க முடியவில்லை. நிறுவலை ரத்துசெய்யவும்."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Dynamic system தற்போது இயக்கத்தில் உள்ளது. அசல் Android பதிப்பைப் பயன்படுத்த மீண்டும் தொடங்கவும்."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"ரத்துசெய்"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"நிராகரி"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
index 6d33979..c2f3dfa 100644
--- a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamik sistem hazır. Kullanmaya başlamak için cihazınızı yeniden başlatın."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Yükleme devam ediyor"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Yükleme başarısız oldu"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Resim doğrulanamadı. Yüklemeyi iptal edin."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Görüntü doğrulanamadı. Yüklemeyi iptal edin."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Şu anda dinamik sistem çalıştırılıyor. Orijinal Android sürümünü kullanmak için cihazı yeniden başlatın."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"İptal"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Sil"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
index df21144..5597fb5 100644
--- a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Dinamik tizim tayyor. Foydalanishni boshlash uchun qurilmani qayta ishga tushiring."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Oʻrnatilmoqda"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Oʻrnatilmadi"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Rasm tekshiruvi amalga oshmadi Oʻrnatishni bekor qilish."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Disk tasviri tekshiruvi amalga oshmadi. Oʻrnatishni bekor qiling."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Hozirda dinamik tizim ishga tushirilgan. Asl Android versiyasidan foydlanish uchun qayta ishga tushiring."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Bekor qilish"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Bekor qilish"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
index 617e9ed..6ef965f 100644
--- a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
@@ -5,7 +5,7 @@
     <string name="notification_install_completed" msgid="6252047868415172643">"Uhlole Okunhlobonhlobo kulungile. Ukuze uqale ukuyisebenzisa, qalisa kabusha idivayisi yakho."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Ukufaka kuyaqhubeka"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Ukufaka kwehlulekile"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ukuqinisekiswa kwesithombe kuhlulekile. Yekisa ukufakwa."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ukuqinisekiswa kwe-disk image kuhlulekile. Yekisa ukufakwa."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Manje iqalisa uhlole olunhlobonhlobo. Qalisa kabusha ukuze usebenzise inguqulo yangempela ye-Android."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Khansela"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"Lahla"</string>
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index 61349d9..f9f1607 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -26,6 +26,7 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationRequest;
+import android.location.LocationResult;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.os.WorkSource;
@@ -167,8 +168,15 @@
         }
 
         @Override
-        public void onReportLocation(Location location) {
-            mLocations.add(location);
+        public void onReportLocation(LocationResult locationResult) {
+            for (int i = 0; i < locationResult.size(); i++) {
+                mLocations.add(locationResult.get(i));
+            }
+        }
+
+        @Override
+        public void onFlushComplete() {
+
         }
 
         public Location getNextLocation(long timeoutMs) throws InterruptedException {
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 19842eb..fa93f0d 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -69,7 +69,7 @@
     <string name="uninstall_failed_app" msgid="5506028705017601412">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿಲ್ಲ."</string>
     <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"ಸಕ್ರಿಯ ಸಾಧನ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"<xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ ಸಕ್ರಿಯ ಸಾಧನ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
-    <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"ಕೆಲವು ಬಳಕೆದಾರರು ಅಥವಾ ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಈ ಆಪ್‌ ಅಗತ್ಯ ಮತ್ತು ಇತರರ ಸಾಧನದಿಂದ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"ಕೆಲವು ಬಳಕೆದಾರರು ಅಥವಾ ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಈ ಆ್ಯಪ್‌ ಅಗತ್ಯ ಮತ್ತು ಇತರರ ಸಾಧನದಿಂದ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"ಈ ಆ್ಯಪ್‌ಗೆ ನಿಮ್ಮ ಪ್ರೊಫೈಲ್‌‌ನ ಅಗತ್ಯವಿದೆ ಮತ್ತು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"ಈ ಆ್ಯಪ್‌ ನಿಮ್ಮ ಸಾಧನ ನಿರ್ವಾಹಕರಿಗೆ ಅಗತ್ಯವಿದೆ ಮತ್ತು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="manage_device_administrators" msgid="3092696419363842816">"ಸಾಧನದ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 5dddf2d..5119c56 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedraade oorfoon"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 27c8319..de82340 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 9a984e2..e61f527 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -562,8 +562,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"تفعيل"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 4592d0b..8d9d71a 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 5984d75..0e74042 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index c2b1487..4cd3b16 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 61e2a75..3902317 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 973873f..a9c80f5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ad174e7..77090ca 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index f1c980f..9409e65 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index c1ef0b3..65687be 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index c101e99..73ed769 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at anvende denne ændring. Genstart nu, eller annuller."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index ab25178..8eb4b85 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index fb0b1ba..d934aeb 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index faa5df3..49e3a7c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index faa5df3..49e3a7c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index faa5df3..49e3a7c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index eeb56c5..5d4c153 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 4656049..9bd3256 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reinicia ahora o cancela la acción."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index abc639b..732b1f5 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index d64d721..9f4bd1a 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index d73f61d..1a5acc4 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راه‌اندازی مجدد شود. اکنون راه‌اندازی مجدد کنید یا لغو کنید."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index b4451eb..9542646 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peruuta."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Poissa päältä"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 3eff351..7367dc3 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 2efa736..f1474ad 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index ee5d899..1e651a4 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 5bb783d..d52d487 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 4cf90fc..9f63344 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, डिवाइस को रीस्टार्ट करना होगा. अपने डिवाइस को रीस्टार्ट करें या रद्द करें."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 5384473..f95f8c1 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 223f783..3167c83 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 14c4f61..e6ef17d 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3792a30..7498472 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index dbd12cc..5e91394 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 0949fd6..e42f109 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Per applicare questa modifica, devi riavviare il dispositivo. Riavvia ora o annulla."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 8380110..e313552 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"כבויה"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a63cfe4..7c15986 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動するか、キャンセルしてください。"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index d8dd26f..dd10e39 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 262afde..4857fe9 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 2161b21..6909af8c 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែ​ចាប់ផ្ដើម​ឧបករណ៍​របស់អ្នក​ឡើងវិញ ដើម្បីឱ្យ​ការផ្លាស់ប្ដូរ​នេះ​មានប្រសិទ្ធភាព។ ចាប់ផ្ដើមឡើងវិញ​ឥឡូវនេះ ឬ​បោះបង់​។"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាស​មានខ្សែ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 4c539cc..40e3f1f2c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -306,7 +306,7 @@
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"ನೀವು ಹಿಂದೆ ಅಧಿಕೃತಗೊಳಿಸಿದ ಎಲ್ಲ ಕಂಪ್ಯೂಟರ್‌ಗಳಿಂದ USB ಡೀಬಗ್‌ಗೆ ಪ್ರವೇಶವನ್ನು ರದ್ದುಗೊಳಿಸುವುದೇ?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"ಅಭಿವೃದ್ಧಿಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಅಭಿವೃದ್ಧಿಯ ಬಳಕೆಗೆ ಮಾತ್ರ. ಅವುಗಳು ನಿಮ್ಮ ಸಾಧನ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳಿಗೆ ಧಕ್ಕೆ ಮಾಡಬಹುದು ಅಥವಾ ಅವು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರುವಂತೆ ಮಾಡಬಹುದು."</string>
-    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ಮೂಲಕ ಆಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
+    <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ಮೂಲಕ ಆ್ಯಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"ಹೆಸರುಗಳಿಲ್ಲದ (ಕೇವಲ MAC ವಿಳಾಸಗಳು ಮಾತ್ರ) ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"ರಿಮೋಟ್ ಸಾಧನಗಳಲ್ಲಿ ಕಂಡುಬರುವ ಸ್ವೀಕಾರಾರ್ಹವಲ್ಲದ ಜೋರಾದ ವಾಲ್ಯೂಮ್ ಅಥವಾ ನಿಯಂತ್ರಣದ ಕೊರತೆಯಂತಹ ವಾಲ್ಯೂಮ್ ಸಮಸ್ಯೆಗಳಂತಹ ಸಂದರ್ಭದಲ್ಲಿ ಬ್ಲೂಟೂತ್‍ನ ನಿಚ್ಚಳ ವಾಲ್ಯೂಮ್ ವೈಶಿಷ್ಟ್ಯವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್‌ಫೋನ್"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್ ಆಗಿದೆ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index fa2eec4..3b7a9e5 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안함"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 6e737cc..44654fc 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөрүү күчүнө кириши үчүн, түзмөктү өчүрүп күйгүзүңүз. Азыр же кийинчерээк өчүрүп күйгүзсөңүз болот."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 3968766..bcb5ad1 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index eee053b..3fc631a 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 161ea77..617a4f1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 0715360..18a62d2 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index a7a5c22..0ff31a61 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c397cb5..2fb4e44 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index abc841d..56d3f0f 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index a0e3714..0ba2102 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်ထားသည်"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်ထားသည်"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 19aa7f1..47150e5 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hodetelefoner med kabel"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 440808d..87bb8d5 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade hoofdtelefoon"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index c67fd47..1fe6d7f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ୍ କରନ୍ତୁ।"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e52f740..934f111 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 9a803d6..edc2cea 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index b288a62..6445b9e 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să reporniți dispozitivul. Reporniți-l acum sau anulați."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index f87d5aa..0b18af8 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 3115067..40327132 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්‍රියාත්මකයි"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්‍රියාවිරහිතයි"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 178408d..4e3529f 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Zmena sa prejaví až po reštarte zariadenia. Môžete ho teraz reštartovať alebo akciu zrušiť."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 517d5c9..22dd5dd 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 5d31885..db29b41 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 8cf7603..97398d0 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -559,8 +559,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index d3afb22..8bdfa0d 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a8cf7fb47..bbd1b8a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 41ebe05..a386739 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a4d7d83..4023897 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్‌ఫోన్"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్‌లో ఉంది"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్‌లో ఉంది"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index fa92d40..4d22fb0 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 2859b71..875bbff 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index bbff7b4..9604c94 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazınızın yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index fff49cd..03eb42c 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -560,8 +560,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, потрібний перезапуск. Перезапустіть пристрій або скасуйте зміни."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index aa38680..12f36fb 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 0928779..aaaa029 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar kuchga kirishi uchun qurilmani oʻchirib yoqing. Buni hozir yoki keyinroq bajarishingiz mumkin."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 512e52f..94494c78 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 0cc2c51..00233c5 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index bd8717f..b83ad35 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"您的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 62dccd3..e5ef613 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 9eb4fea..ba30700 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -558,8 +558,6 @@
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
-    <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
-    <skip />
-    <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
-    <skip />
+    <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
+    <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 48421ce..4d054ec 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -992,6 +992,15 @@
     <string name="standby_bucket_summary">App standby
         state:<xliff:g id="bucket"> %s</xliff:g></string>
 
+    <!-- Settings item title for transcode settings for apps. [CHAR LIMIT=85] -->
+    <string name="transcode_settings_title">Media transcode settings</string>
+
+    <!-- Settings item title to enable or disable transcoding for all apps. [CHAR LIMIT=85] -->
+    <string name="transcode_enable_all">Enable transcoding for all apps</string>
+
+    <!-- Settings category title for selecting apps to be skipped from transcoding. [CHAR LIMIT=85] -->
+    <string name="transcode_skip_apps">Disable transcoding for apps</string>
+
     <!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
     <string name="runningservices_settings_title">Running services</string>
     <!-- Services settings screen, setting option summary for the user to go to the screen to view running services  -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 38ff447..2e551fa 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -888,8 +888,8 @@
                 Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
                 GlobalSettingsProto.Location.SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.GNSS_SATELLITE_BLACKLIST,
-                GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
+                Settings.Global.GNSS_SATELLITE_BLOCKLIST,
+                GlobalSettingsProto.Location.GNSS_SATELLITE_BLOCKLIST);
         dumpSetting(s, p,
                 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
                 GlobalSettingsProto.Location.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 36213a0..a61e3cd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3342,7 +3342,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 194;
+            private static final int SETTINGS_VERSION = 195;
 
             private final int mUserId;
 
@@ -4761,6 +4761,22 @@
                     currentVersion = 194;
                 }
 
+                if (currentVersion == 194) {
+                    // Version 194: migrate the GNSS_SATELLITE_BLOCKLIST setting
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    final Setting newSetting = globalSettings.getSettingLocked(
+                            Global.GNSS_SATELLITE_BLOCKLIST);
+                    final String oldName = "gnss_satellite_blacklist";
+                    final Setting oldSetting = globalSettings.getSettingLocked(oldName);
+                    if (newSetting.isNull() && !oldSetting.isNull()) {
+                        globalSettings.insertSettingLocked(
+                                Global.GNSS_SATELLITE_BLOCKLIST, oldSetting.getValue(), null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                        globalSettings.deleteSettingLocked(oldName);
+                    }
+                    currentVersion = 195;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 48eb600..a3bda96 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -291,7 +291,7 @@
                     Settings.Global.GLOBAL_HTTP_PROXY_PAC,
                     Settings.Global.GLOBAL_HTTP_PROXY_PORT,
                     Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
-                    Settings.Global.GNSS_SATELLITE_BLACKLIST,
+                    Settings.Global.GNSS_SATELLITE_BLOCKLIST,
                     Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
                     Settings.Global.HDMI_CEC_SWITCH_ENABLED,
                     Settings.Global.HDMI_CEC_VERSION,
diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml
index a617733..c39db5f 100644
--- a/packages/SoundPicker/res/values-uz/strings.xml
+++ b/packages/SoundPicker/res/values-uz/strings.xml
@@ -20,7 +20,7 @@
     <string name="notification_sound_default" msgid="8133121186242636840">"Standart bildirishnoma tovushi"</string>
     <string name="alarm_sound_default" msgid="4787646764557462649">"Standart signal tovushi"</string>
     <string name="add_ringtone_text" msgid="6642389991738337529">"Rington qo‘shish"</string>
-    <string name="add_alarm_text" msgid="3545497316166999225">"Signal qo‘shish"</string>
+    <string name="add_alarm_text" msgid="3545497316166999225">"Signal kiritish"</string>
     <string name="add_notification_text" msgid="4431129543300614788">"Bildirishnoma kiritish"</string>
     <string name="delete_ringtone_text" msgid="201443984070732499">"O‘chirish"</string>
     <string name="unable_to_add_ringtone" msgid="4583511263449467326">"Maxsus rington qo‘shib bo‘lmadi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 4607981..0948871 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -72,7 +72,7 @@
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduce o PIN da SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
     <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desactiva a eSIM para usar o dispositivo sen o servizo móbil."</string>
     <string name="kg_pin_instructions" msgid="822353548385014361">"Introduce o PIN"</string>
-    <string name="kg_password_instructions" msgid="324455062831719903">"Insire o teu contrasinal"</string>
+    <string name="kg_password_instructions" msgid="324455062831719903">"Escribe o teu contrasinal"</string>
     <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"Agora a tarxeta SIM está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter máis información."</string>
     <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"Agora a SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter máis información."</string>
     <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Introduce o código PIN desexado"</string>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
new file mode 100644
index 0000000..257bf35
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="1"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
new file mode 100644
index 0000000..e032008
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="0"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
new file mode 100644
index 0000000..257bf35
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="1"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
new file mode 100644
index 0000000..e032008
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:propertyName="alpha"
+    android:valueTo="0"
+    android:interpolator="@android:interpolator/fast_out_slow_in"
+    android:duration="100" />
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 0000000..6a0695e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/transparent" />
+    <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_pause_white.xml b/packages/SystemUI/res/drawable/ic_pause_white.xml
new file mode 100644
index 0000000..5b65f10
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_pause_white.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
new file mode 100644
index 0000000..ddc9e8d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M8 5v14l11-7z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/packages/SystemUI/res/drawable/pip_icon.xml
new file mode 100644
index 0000000..bd92ccd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="36dp"
+    android:height="36dp"
+    android:viewportWidth="25"
+    android:viewportHeight="25">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_resize_handle.xml b/packages/SystemUI/res/drawable/pip_resize_handle.xml
new file mode 100644
index 0000000..0a8cbc4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_resize_handle.xml
@@ -0,0 +1,29 @@
+<?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="12.0dp"
+    android:height="12.0dp"
+    android:viewportWidth="12"
+    android:viewportHeight="12">
+    <group
+        android:translateX="12"
+        android:rotation="90">
+        <path
+          android:fillColor="#FFFFFF"
+          android:pathData="M3.41421 0L2 1.41422L10.4853 9.8995L11.8995 8.48528L3.41421 0ZM2.41421 4.24268L1 5.65689L6.65685 11.3137L8.07107 9.89953L2.41421 4.24268Z" />
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
new file mode 100644
index 0000000..2b33e17
--- /dev/null
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/background"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!-- Menu layout -->
+    <FrameLayout
+        android:id="@+id/menu_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:forceHasOverlappingRendering="false"
+        android:accessibilityTraversalAfter="@id/dismiss">
+
+        <!-- The margins for this container is calculated in the code depending on whether the
+             actions_container is visible. -->
+        <FrameLayout
+            android:id="@+id/expand_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <ImageButton
+                android:id="@+id/expand_button"
+                android:layout_width="60dp"
+                android:layout_height="60dp"
+                android:layout_gravity="center"
+                android:contentDescription="@string/pip_phone_expand"
+                android:padding="10dp"
+                android:src="@drawable/pip_expand"
+                android:background="?android:selectableItemBackgroundBorderless" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/actions_container"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/pip_action_size"
+            android:layout_gravity="bottom"
+            android:visibility="invisible">
+            <LinearLayout
+                android:id="@+id/actions_group"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_horizontal"
+                android:orientation="horizontal"
+                android:divider="@android:color/transparent"
+                android:showDividers="middle" />
+        </FrameLayout>
+    </FrameLayout>
+
+    <ImageButton
+        android:id="@+id/settings"
+        android:layout_width="@dimen/pip_action_size"
+        android:layout_height="@dimen/pip_action_size"
+        android:layout_gravity="top|start"
+        android:padding="@dimen/pip_action_padding"
+        android:contentDescription="@string/pip_phone_settings"
+        android:src="@drawable/ic_settings"
+        android:background="?android:selectableItemBackgroundBorderless" />
+
+    <ImageButton
+        android:id="@+id/dismiss"
+        android:layout_width="@dimen/pip_action_size"
+        android:layout_height="@dimen/pip_action_size"
+        android:layout_gravity="top|end"
+        android:padding="@dimen/pip_action_padding"
+        android:contentDescription="@string/pip_phone_close"
+        android:src="@drawable/ic_close_white"
+        android:background="?android:selectableItemBackgroundBorderless" />
+
+    <!--TODO (b/156917828): Add content description for a11y purposes?-->
+    <ImageButton
+        android:id="@+id/resize_handle"
+        android:layout_width="@dimen/pip_resize_handle_size"
+        android:layout_height="@dimen/pip_resize_handle_size"
+        android:layout_gravity="top|start"
+        android:layout_margin="@dimen/pip_resize_handle_margin"
+        android:src="@drawable/pip_resize_handle"
+        android:background="?android:selectableItemBackgroundBorderless" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
new file mode 100644
index 0000000..b9b0154
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.pip.tv.PipControlButtonView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <ImageView android:id="@+id/button"
+        android:layout_width="34dp"
+        android:layout_height="34dp"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:focusable="true"
+        android:src="@drawable/tv_pip_button_focused"
+        android:importantForAccessibility="yes" />
+
+    <ImageView android:id="@+id/icon"
+        android:layout_width="34dp"
+        android:layout_height="34dp"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:padding="5dp"
+        android:importantForAccessibility="no" />
+
+    <TextView android:id="@+id/desc"
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/icon"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="3dp"
+        android:gravity="center"
+        android:text="@string/pip_fullscreen"
+        android:alpha="0"
+        android:fontFamily="sans-serif"
+        android:textSize="12sp"
+        android:textColor="#EEEEEE"
+        android:importantForAccessibility="no" />
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
new file mode 100644
index 0000000..0b7bce1
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.pip.tv.PipControlsView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <com.android.systemui.pip.tv.PipControlButtonView
+        android:id="@+id/full_button"
+        android:layout_width="@dimen/picture_in_picture_button_width"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_fullscreen_white_24dp"
+        android:text="@string/pip_fullscreen" />
+
+    <com.android.systemui.pip.tv.PipControlButtonView
+        android:id="@+id/close_button"
+        android:layout_width="@dimen/picture_in_picture_button_width"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
+        android:src="@drawable/ic_close_white"
+        android:text="@string/pip_close" />
+
+    <com.android.systemui.pip.tv.PipControlButtonView
+        android:id="@+id/play_pause_button"
+        android:layout_width="@dimen/picture_in_picture_button_width"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
+        android:src="@drawable/ic_pause_white"
+        android:text="@string/pip_pause"
+        android:visibility="gone" />
+</merge>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 8362847..1fab478 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probeer weer skermkiekie neem"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Wysig"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Wysig skermkiekie"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rollees"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rollees skermskoot"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Maak skermkiekie toe"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Skermkiekievoorskou"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Skermopnemer"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 3aeeb86..eb63165 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofoon aktief"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s het toegang tot jou mikrofoon"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is gekoppel"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is ontkoppel"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a36e0e2..5153904 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ቅጽበታዊ ገጽ ዕይታን እንደገና ማንሳት ይሞክሩ"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ባለው ውሱን የማከማቻ ቦታ ምክንያት ቅጽበታዊ ገጽ ዕይታን ማስቀመጥ አይችልም"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"አርትዕ ያድርጉ"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ቅጽበታዊ ገጽ ዕይታን አርትዕ ያድርጉ"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"ሸብልል"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"ቅጽበታዊ ገጽ ዕይታን ይሸብልሉ"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ቅጽበታዊ ገጽ ዕይታን አሰናብት"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"የቅጽበታዊ ገጽ ዕይታ ቅድመ-ዕይታ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index 66847d1..3ba5a62 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ማይክራፎን ንቁ ነው"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s የእርስዎን ማይክራፎን ደርሶበታል"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ተያይዟል"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ተቋርቷል"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"በ<xliff:g id="VPN_APP">%1$s</xliff:g> በኩል"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a976a76..f6a1cf5 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"جرّب أخذ لقطة الشاشة مرة أخرى"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"يتعذر حفظ لقطة الشاشة لأن مساحة التخزين المتاحة محدودة."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"يحظر التطبيق أو تحظر مؤسستك التقاط لقطات شاشة"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"تعديل"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"تعديل لقطة الشاشة"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"الانتقال خلال الشاشة"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"لقطة شاشة موصولة"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"إغلاق لقطة الشاشة"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"معاينة لقطة الشاشة"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index 9f93057..15ccb94 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"الميكروفون نشط"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"‏تمكن %1$s من الوصول إلى الميكروفون الخاص بك."</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"‏الشبكة الافتراضية الخاصة (VPN) متصلة."</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏الشبكة الافتراضية الخاصة (VPN) غير متصلة."</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"عبر <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 118c627..f7afcfa 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"মাইক্ৰ’ফ’ন সক্ৰিয় কৰা আছে"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$sএ আপোনাৰ মাইক্ৰ’ফ’ন এক্সেছ কৰিছে"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"ভিপিএন সংযোগ হৈ আছে"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ভিপিএনৰ সংযোগ বিচ্ছিন্ন হৈছে"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>ৰ জৰিয়তে"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index 037eb7c..cd9935f 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktivdir"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofona daxil olub"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN qoşulub"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ayrılıb"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> vasitəsilə"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index 5f03299..8122e4d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivan"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je pristupila mikrofonu"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je povezan"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Veza sa VPN-om je prekinuta"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Preko: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index 7433d15..1016b8c 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Мікрафон актыўны"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Праграма \"%1$s\" атрымала доступ да мікрафона"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN падключаны"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN адключаны"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Праз <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index 630e92d..6f6b824 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофонът е активен"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s осъществи достъп до микрофона ви"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN е свързана"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Връзката с VPN е прекратена"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Чрез <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index 55e9fbf..7507746 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivan"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je pristupila vašem mikrofonu"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je povezan"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Veza s VPN-om je prekinuta"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index fed1839..ca63162 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,10 +33,10 @@
     <string name="invalid_charger_title" msgid="938685362320735167">"No es pot carregar per USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Fes servir el carregador original del dispositiu"</string>
     <string name="battery_low_why" msgid="2056750982959359863">"Configuració"</string>
-    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar l\'estalvi de bateria?"</string>
+    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar la funció Estalvi de bateria?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre la funció Estalvi de bateria"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activa"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa l\'estalvi de bateria"</string>
+    <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa la funció Estalvi de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Gira pantalla automàticament"</string>
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prova de tornar a fer una captura de pantalla"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'aplicació o la teva organització no permeten fer captures de pantalla"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Edita"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Edita la captura de pantalla"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desplaça"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Captura de pantalla lliscant"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora la captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Previsualització de la captura de pantalla"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
@@ -508,7 +503,7 @@
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Suprimeix"</string>
     <string name="battery_saver_notification_title" msgid="8419266546034372562">"S\'ha activat l\'estalvi de bateria"</string>
     <string name="battery_saver_notification_text" msgid="2617841636449016951">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
-    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva l\'estalvi de bateria"</string>
+    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva la funció Estalvi de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index a93e294..14bc947 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micròfon actiu"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha accedit al teu micròfon"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN està connectada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN està desconnectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Mitjançant <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index d91fae9..aa6459e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zkuste snímek pořídit znovu"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Snímek obrazovky kvůli nedostatku místa v úložišti nelze uložit"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Upravit"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Upravit snímek obrazovky"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Posunout"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Posunout snímek obrazovky"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavřít snímek obrazovky"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Náhled snímku obrazovky"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index d916e61..ad869b1 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivní"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikace %1$s použila mikrofon"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Síť VPN je připojena"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Síť VPN je odpojena"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prostřednictvím aplikace <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index 2072f1e..84926e0c 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofonen er slået til"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fik adgang til din mikrofon"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tilsluttet"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er afbrudt"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 21c371e..dcd6a53 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Versuche noch einmal, den Screenshot zu erstellen"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Speichern des Screenshots aufgrund von zu wenig Speicher nicht möglich"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die App oder deine Organisation lässt das Erstellen von Screenshots nicht zu"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Bearbeiten"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bearbeiten"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scrollen"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index d0ff804..197cd17 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Δοκιμάστε να κάνετε ξανά λήψη του στιγμιότυπου οθόνης"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου αποθηκευτικού χώρου"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Η λήψη στιγμιότυπων οθόνης δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Επεξεργασία"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Επεξεργασία στιγμιότυπου οθόνης"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Κύλιση"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Στιγμιότυπο κύλισης"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Παράβλεψη στιγμιότυπου οθόνης"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Προεπισκόπηση στιγμιότυπου οθόνης"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Εγγραφή οθόνης"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index 8a7eea4..21badf7 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Ενεργό μικρόφωνο"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Πραγματοποιήθηκε πρόσβαση στο μικρόφωνό σας από το %1$s"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Το VPN συνδέθηκε"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Το VPN αποσυνδέθηκε"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Μέσω <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index b3dd86a..ab370b1 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings_tv.xml b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
index b3dd86a..ab370b1 100644
--- a/packages/SystemUI/res/values-en-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index b3dd86a..ab370b1 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index b3dd86a..ab370b1 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d8e1234..bd64950 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a hacer una captura de pantalla"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"No se puede guardar la captura de pantalla debido a que no hay suficiente espacio de almacenamiento"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La app o tu organización no permiten las capturas de pantalla"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desplazar"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Desplazar captura de pantalla"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Descartar captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de la captura de pantalla"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 17544e7..7aa9927 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micrófono activado"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accedió al micrófono"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN está conectada."</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN está desconectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index d1034a7..d9b805b 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a intentar hacer la captura de pantalla"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desplazarse"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Desplazarse por la captura de pantalla"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cerrar captura de pantalla"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de captura de pantalla"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 40340d8..f3bab28 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micrófono activado"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha accedido a tu micrófono"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN está conectada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN está desconectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 847d2b7..c11f21c 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Proovige ekraanipilt uuesti jäädvustada"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Muutmine"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekraanipildi muutmine"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Kerimine"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ekraanipildi kerimine"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekraanipildist loobumine"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekraanipildi eelvaade"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index 329311a..c59b5bc 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon on aktiivne"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s pääses teie mikrofonile juurde"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN on ühendatud"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-i ühendus on katkestatud"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"VPN-i <xliff:g id="VPN_APP">%1$s</xliff:g> kaudu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index d17c533..453d32e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Saiatu berriro pantaila-argazkia ateratzen"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Ezin da gorde pantaila-argazkia ez delako gelditzen tokirik"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Editatu"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Editatu pantaila-argazkia"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Egin gora eta behera"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pantaila-kaptura etengabea"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Baztertu pantaila-argazkia"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pantaila-argazkiaren aurrebista"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index b311ecc..67cb078 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofonoa aktibatuta dago"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s aplikazioak mikrofonoa atzitu du"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN sarera konektatuta dago"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ez dago sarera konektatuta"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> bidez"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 07a5dae..55ca0f3 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوباره نماگرفت بگیرید"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توان نماگرفت را ذخیره کرد"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"برنامه یا سازمان شما اجازه نمی‌دهند نماگرفت بگیرید."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ویرایش"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ویرایش نماگرفت"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"پیمایش"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"نماگرفت پیمایشی"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کردن نماگرفت"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"پیش‌نمایش نماگرفت"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ضبط‌کننده صفحه‌نمایش"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحه‌نمایش"</string>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index c6931a9..37aaa64 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"میکروفون فعال است"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s به میکروفون شما دسترسی پیدا کرد"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"‏VPN متصل است"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏VPN قطع است"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ازطریق <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 835e32f..f5441a2 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Yritä ottaa kuvakaappaus uudelleen."</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kuvakaappauksen tallennus epäonnistui, sillä tallennustilaa ei ole riittävästi"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Sovellus tai organisaatio ei salli kuvakaappauksien tallentamista."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Muuta"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Muokkaa kuvakaappausta"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Vieritä"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Vieritä kuvakaappausta"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hylkää kuvakaappaus"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Kuvakaappauksen esikatselu"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 6c84e58..295780b 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofoni aktiivinen"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s sai pääsyn mikrofoniisi"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN on yhdistetty"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ei ole yhdistettynä"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Palvelun <xliff:g id="VPN_APP">%1$s</xliff:g> kautta"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index e1b15b3..332b440 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de faire une autre capture d\'écran"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Faire défiler"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Faire défiler la capture d\'écran"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index 09dbec2..696e959 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microphone actif"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accédé à votre microphone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"RPV connecté"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"RPV déconnecté"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Par <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4cfdaea..62e653c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de nouveau de faire une capture d\'écran"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Les captures d\'écran ne sont pas autorisées par l\'application ni par votre organisation"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Faire défiler"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Faire défiler la capture d\'écran"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 9ebb17d..f2c5d97 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micro actif"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accédé à votre micro"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN connecté"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN déconnecté"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index 6c48267..095386b 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micrófono activo"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accedeu ao teu micrófono"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 44cb199d..35d4e1a 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ફરીથી સ્ક્રીનશૉટ લેવાનો પ્રયાસ કરો"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"મર્યાદિત સ્ટોરેજ સ્પેસને કારણે સ્ક્રીનશૉટ સાચવી શકાતો નથી"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશૉટ લેવાની મંજૂરી નથી"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ફેરફાર કરો"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"સ્ક્રીનશૉટમાં ફેરફાર કરો"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"સ્ક્રોલ કરો"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"સ્ક્રીનશૉટ પર સ્ક્રોલ કરો"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 89c1756..1d02fd0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट दोबारा लेने की कोशिश करें"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"मेमोरी कम होने की वजह से स्क्रीनशॉट सेव नहीं किया जा सका"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ऐप्लिकेशन या आपका संगठन स्क्रीनशॉट लेने की अनुमति नहीं देता"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"बदलाव करें"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट में बदलाव करें"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"स्क्रोल करें"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉट को स्क्रोल करें"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट को खारिज करें"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index df68864..d2ce7a9 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"माइक्रोफ़ोन चालू है"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ने आपका माइक्रोफ़ोन ऐक्सेस किया था"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"वीपीएन कनेक्ट हो गया है"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"वीपीएन डिसकनेक्ट हो गया है"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> के ज़रिए"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 40ebad5..9c4939c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pokušajte ponovo napraviti snimku zaslona"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Zaslon nije snimljen zbog ograničenog prostora za pohranu"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili vaša organizacija ne dopuštaju snimanje zaslona"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Uređivanje snimke zaslona"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Pomakni"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pomicanje snimke zaslona"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacivanje snimke zaslona"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimke zaslona"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Snimač zaslona"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index b6bfbba..ee29a6c 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon aktivan"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s pristupila je mikrofonu"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je spojen"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN je isključen"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem mreže <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 050982e..2feb1b2 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Próbálja meg újra elkészíteni a képernyőképet"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Nem menthet képernyőképet, mert kevés a tárhely"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Az alkalmazás vagy az Ön szervezete nem engedélyezi képernyőkép készítését"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Szerkesztés"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Képernyőkép szerkesztése"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Görgetés"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Görgethető képernyőkép"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Képernyőkép elvetése"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Képernyőkép előnézete"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index f34d7e0..cbbebb0 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"A mikrofon aktív"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"A(z) %1$s hozzáfért a mikrofonhoz"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN-kapcsolat létrejött"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN-kapcsolat megszakadt"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A következő szolgáltatás használatával: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d8ea997..0258e44 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Փորձեք նորից"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Չհաջողվեց պահել սքրինշոթը անբավարար հիշողության պատճառով"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում սքրինշոթի ստացումը"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Փոփոխել"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Փոփոխել սքրինշոթը"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Ոլորել"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ոլորել սքրինշոթը"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Փակել սքրինշոթը"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Սքրինշոթի նախադիտում"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
@@ -1079,6 +1074,6 @@
     <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
     <string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
     <string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
-    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչը կարդալու հետ կապված խնդիր կա"</string>
+    <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index 3ed3ecf..58c5149 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Խոսափողն ակտիվացված է"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s հավելվածն օգտագործել է ձեր խոսափողը"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-ը միացված է"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-ն անջատված է"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2a294c4..bea37ae 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Coba ambil screenshot lagi"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Tidak dapat menyimpan screenshot karena ruang penyimpanan terbatas"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Mengambil screenshot tidak diizinkan oleh aplikasi atau organisasi"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Mengedit screenshot"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Men-scroll screenshot"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Menutup screenshot"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pratinjau screenshot"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index 315796e..bdd6742 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mengakses mikrofon"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN tersambung"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN terputus"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index 30456d4..88a4315 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Hljóðnemi virkur"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fékk aðgang að hljóðnemanum þínum"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tengt"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er ekki tengt"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Í gegnum <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ef2d6cf..026b5a9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Riprova ad acquisire lo screenshot"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossibile salvare lo screenshot a causa dello spazio di archiviazione limitato"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifica"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifica screenshot"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scorri"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scorri screenshot"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora screenshot"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Anteprima screenshot"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 6c45e35..97badc1 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfono attivo"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha avuto accesso al tuo microfono"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN connessa"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN disconnessa"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Tramite <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 708032a..b4df62b 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"יש לנסות שוב לבצע צילום מסך"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"לא היה מספיק מקום לשמור את צילום המסך"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"עריכה"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"עריכת צילום מסך"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"גלילה"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"צילום מסך נגלל"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index f2d51f5a..45d744a 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"המיקרופון פעיל"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s קיבלה גישה למיקרופון שלך"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"‏VPN מחובר"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏VPN מנותק"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"באמצעות <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index c501865..9d7a36a 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"マイク: 有効"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s がマイクにアクセスしました"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN に接続しました"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN に接続していません"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> 経由"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 272c3b4..6fdb8b8 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ხელახლა ცადეთ ეკრანის ანაბეჭდის გაკეთება"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"რედაქტირება"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ეკრანის ანაბეჭდის რედაქტირება"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"გრაგნილი"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"ეკრანის ანაბეჭდში გადაადგილება"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ეკრანის ანაბეჭდის დახურვა"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ეკრანის ანაბეჭდის გადახედვა"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index 607f6ce..0dc1e10 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"მიკროფონი აქტიურია"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s-მა გამოიყენა თქვენი მიკროფონი"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN დაკავშირებულია"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN გათიშულია"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ის მიერ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 93af68c..160e05d 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Қайта скриншот жасап көріңіз"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Жадтағы шектеулі бос орынға байланысты скриншот сақталмайды"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Өзгерту"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотты өзгерту"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Айналдыру"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Скриншотты айналдыру"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотты жабу"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотты алдын ала қарау"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 2c72710..cc15978 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофон қосулы"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s микрофоныңызды пайдаланды."</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN қосылған"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ажыратылған"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> арқылы жалғанған"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e6c5106c..e559c19 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"សាកល្បង​ថតរូបថត​អេក្រង់​ម្តងទៀត"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"មិនអាច​រក្សាទុក​រូបថតអេក្រង់​បានទេ ​ដោយសារ​ទំហំផ្ទុក​មានកម្រិតទាប"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ការថត​រូបអេក្រង់​មិនត្រូវ​បាន​អនុញ្ញាត​ដោយ​កម្មវិធី​នេះ ឬ​ស្ថាប័ន​របស់អ្នក"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"កែ"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"កែ​រូបថត​អេក្រង់"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"រំកិល"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"មុខងារ​ថតរូបថត​អេក្រង់​រំកិល"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ច្រានចោល​រូបថត​អេក្រង់"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ការមើល​រូបថត​អេក្រង់​សាកល្បង"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថត​អេក្រង់"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុង​ដំណើរការ​ការថតអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index db3487e..f415a66 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"មីក្រូហ្វូន​កំពុង​ដំណើរការ"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s បានចូលប្រើ​មីក្រូហ្វូន​របស់អ្នក"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ត្រូវបានភ្ជាប់"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ត្រូវបានផ្ដាច់"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"តាម​រយៈ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 70dac4c..f121080 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ಪುನಃ ತೆಗೆದುಕೊಳ್ಳಲು ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳದ ಕಾರಣದಿಂದಾಗಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸಂಸ್ಥೆಯು ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ತೆಗೆಯುವುದನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ಎಡಿಟ್ ಮಾಡಿ"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ಸ್ಕ್ರೀನ್‍ಶಾಟ್‍ನ ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index 6f7c31d..a935963 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ಮೈಕ್ರೋಫೋನ್‌ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ನಿಮ್ಮ ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿದೆ"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ಕನೆಕ್ಷನ್ ಕಡಿತಗೊಂಡಿದೆ"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ಮೂಲಕ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index 5424a84..8c3a8ea 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"마이크 사용 중"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s에서 내 마이크에 액세스했습니다."</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN에 연결됨"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 연결이 해제됨"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결됨"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index 8d8cdda..3be657c 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофон күйүк"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s микрофонуңузду колдонууда"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN туташтырылды"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ажыратылды"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> аркылуу"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index 37025a7..445e562 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ໄມໂຄຣໂຟນເປີດໃຊ້ຢູ່"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ເຂົ້າເຖິງໄມໂຄຣໂຟນຂອງທ່ານແລ້ວ"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"ເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ຕັດການເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ຜ່ານ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 670d8ba5..c749cdf 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofonas aktyvus"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"„%1$s“ pasiekė jūsų mikrofoną"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN prijungtas"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN atjungtas"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Per „<xliff:g id="VPN_APP">%1$s</xliff:g>“"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 8c6676e..da8adb4 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Mēģiniet izveidot jaunu ekrānuzņēmumu."</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediģēt"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediģēt ekrānuzņēmumu"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Ritināt"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ritināt ekrānuzņēmumu"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Nerādīt ekrānuzņēmumu"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrānuzņēmuma priekšskatījums"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index 82a1a0a..f752439 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofons ir aktīvs"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Lietotne %1$s piekļuva jūsu mikrofonam"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Savienojums ar VPN ir izveidots."</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Savienojums ar VPN ir pārtraukts."</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Izmantojot: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index 17e7255..9472813 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофонот е активен"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s пристапи до вашиот микрофон"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN е поврзана"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN е исклучена"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преку <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 5de8830..4d77fcd 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"സ്‌ക്രീൻഷോട്ട് എടുക്കാൻ വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"സ്‌റ്റോറേജ് ഇടം പരിമിതമായതിനാൽ സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കാനാകുന്നില്ല"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"എഡിറ്റ് ചെയ്യുക"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"സ്ക്രീൻഷോട്ട് എഡിറ്റ് ചെയ്യുക"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"സ്‌ക്രോൾ ചെയ്യുക"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"സ്ക്രീൻഷോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്‌മിസ് ചെയ്യുക"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"സ്‌ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index b9a6dbe..fe79796 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"മൈക്രോഫോൺ സജീവമാണ്"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s, നിങ്ങളുടെ മൈക്രോഫോൺ ആക്‌സസ് ചെയ്‌തു"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN കണക്റ്റ് ചെയ്‌തു"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN വിച്ഛേദിച്ചു"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> വഴി"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index 3aef055..9ec66d1 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофон идэвхтэй байна"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s нь таны микрофонд хандcан байна"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN холбогдсон"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN салсан"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-р"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index 91c8c47..65c8068 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s telah mengakses mikrofon anda"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN telah disambungkan"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN diputuskan sambungan"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index 05387e1..c07b9a5 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"မိုက်ခရိုဖုန်း ဖွင့်ထားသည်"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s က သင့်မိုက်ခရိုဖုန်းကို သုံးထားသည်"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ချိတ်ဆက်ထားသည်"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ချိတ်ဆက်မှုမရှိပါ"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> မှတစ်ဆင့်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index cd0ec71..1d30e2b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prøv å ta skjermdump på nytt"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kan ikke lagre skjermdumpen på grunn av begrenset lagringsplass"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger skjermdumpen"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rull"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rull skjermdumpen"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Avvis skjermdumpen"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning av skjermdump"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index 2f69a6c..6346519 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofonen er aktiv"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fikk tilgang til mikrofonen din"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tilkoblet"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er frakoblet"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 55dea83..11f70b4 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfoon actief"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s heeft toegang tot je microfoon gehad"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Verbinding met VPN"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Geen verbinding met VPN"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3483e8c..a809da3 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ପୁଣିଥରେ ସ୍କ୍ରୀନ୍‌ଶଟ୍ ନେବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ସୀମିତ ଷ୍ଟୋରେଜ୍‍ ସ୍ପେସ୍‍ ହେତୁ ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ ହୋଇପାରିବ ନାହିଁ"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ଆପ୍‍ କିମ୍ବା ସଂସ୍ଥା ଦ୍ୱାରା ସ୍କ୍ରୀନଶଟ୍‍ ନେବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ସ୍କ୍ରିନସଟ୍ ଏଡିଟ୍ କରନ୍ତୁ"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"ସ୍କ୍ରିନସଟ୍ ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ସ୍କ୍ରିନସଟ୍ ଖାରଜ କରନ୍ତୁ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ସ୍କ୍ରିନସଟର ପ୍ରିଭ୍ୟୁ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
diff --git a/packages/SystemUI/res/values-or/strings_tv.xml b/packages/SystemUI/res/values-or/strings_tv.xml
index 36623b8..f436bab 100644
--- a/packages/SystemUI/res/values-or/strings_tv.xml
+++ b/packages/SystemUI/res/values-or/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ମାଇକ୍ରୋଫୋନ୍ ସକ୍ରିୟ"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ଆପଣଙ୍କର ମାଇକ୍ରୋଫୋନ୍‌କୁ ଆକ୍ସେସ୍ କରିଛି"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ସଂଯୋଗ କରାଯାଇଛି"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ମାଧ୍ୟମରେ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9eac7df..d9a6828 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੁਬਾਰਾ ਲੈ ਕੇ ਦੇਖੋ"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਹੋਣ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index b623fea..d10daa8 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਕਿਰਿਆਸ਼ੀਲ"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ਨੇ ਤੁਹਾਡੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਤੱਕ ਪਹੁੰਚ ਕੀਤੀ"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ਕਨੈਕਟ ਹੈ"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ਡਿਸਕਨੈਕਟ ਹੈ"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ਰਾਹੀਂ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 2c80194..d83391e 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon aktywny"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s uzyskała dostęp do mikrofonu"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Połączono z VPN"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Rozłączono z VPN"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Przez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index 2b76a8c..49b923d 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acessou seu microfone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 4c97018..dcaf460 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Experimente voltar a efetuar a captura de ecrã."</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Não é possível guardar a captura de ecrã devido a espaço de armazenamento limitado."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A app ou a sua entidade não permitem tirar capturas de ecrã"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de ecrã"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Deslocar"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Deslocar captura de ecrã"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar captura de ecrã"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index ea551d4..a36a1a92 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acedeu ao microfone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está ligada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desligada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Através de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index 2b76a8c..49b923d 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acessou seu microfone"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d2c5a0b..81caf56 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Încercați să faceți din nou o captură de ecran"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Captura de ecran nu poate fi salvată din cauza spațiului de stocare limitat"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Editați"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Editați captura de ecran"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Derulați"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Derulați captura de ecran"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închideți captura de ecran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index 04b0a07..69a3138 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Microfon activ"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accesat microfonul"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN este conectat"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN este deconectat"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 4c235ed..bf5e604 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Попробуйте сделать скриншот снова."</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Не удалось сохранить скриншот: недостаточно места."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Изменить"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Изменить скриншот"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Прокрутить"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Прокрутить скриншот"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрыть скриншот"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Предварительный просмотр скриншота"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index a9752ee..bd8855b 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофон включен"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Приложение \"%1$s\" использовало доступ к микрофону."</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-подключение установлено"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-подключение отключено"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Отправлено через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index a1ac371..a04d166 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"මයික්‍රොෆෝනය සක්‍රියයි"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ඔබේ මයික්‍රොෆෝනයට ප්‍රවේශ වී ඇත"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN සම්බන්ධිතයි"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN විසන්ධි කර ඇත"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> හරහා"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 63a31ce..c2a94be 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Skúste snímku urobiť znova"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Snímka obrazovky sa nedá uložiť z dôvodu nedostatku miesta v úložisku"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Upraviť"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Upraviť snímku obrazovky"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Posúvanie"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Posúvať snímku obrazovky"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavrieť snímku obrazovky"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ukážka snímky obrazovky"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index a83cf40..3b8fcc8 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofón je aktívny"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikácia %1$s použila váš mikrofón"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Sieť VPN je pripojená"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Sieť VPN je odpojená"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Cez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ef22798..5828d65 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Poskusite znova ustvariti posnetek zaslona"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Shranjevanje posnetka zaslona ni mogoče zaradi omejenega prostora za shranjevanje"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ali vaša organizacija ne dovoljuje posnetkov zaslona"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Urejanje posnetka zaslona"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Drseče pomikanje"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Drseče pomikanje po posnetku zaslona"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Opusti posnetek zaslona"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Predogled posnetka zaslona"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 81f69d9..af5d75d 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktiven"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je dostopala do mikrofona"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Povezava z navideznim zasebnim omrežjem je vzpostavljena"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Povezava z navideznim zasebnim omrežjem je prekinjena"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prek storitve <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c401d6c..f9262b0 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Пробајте да поново направите снимак екрана"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Чување снимка екрана није успело због ограниченог меморијског простора"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликација или организација не дозвољавају прављење снимака екрана"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Измените снимак екрана"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Померај"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Померајте снимак екрана"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Одбаците снимак екрана"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед снимка екрана"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index 21fef7f..77f842c 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Микрофон је активан"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Апликација %1$s је приступила микрофону"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN је повезан"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Веза са VPN-ом је прекинута"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преко: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 367297e..3401294 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Testa att ta en skärmdump igen"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisationen tillåter inte att du tar skärmdumpar"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Redigera"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Redigera skärmdump"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scrolla"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rullande skärmdump"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Stäng skärmdump"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Förhandsgranskning av skärmdump"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Skärminspelare"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index ad58bfe..141aabf 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofonen är aktiv"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har fått åtkomst till mikrofonen"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN är anslutet"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN är frånkopplat"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 5d24972..9dd37ce 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Maikrofoni Inatumika"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s imefikia maikrofoni yako"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN imeunganishwa"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN imeondolewa"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Kupitia <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 4ead6cc..0483201 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"மைக்ரோஃபோன் செயலிலுள்ளது"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s உங்கள் மைக்ரோஃபோனைப் பயன்படுத்தியது"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN இணைக்கப்பட்டது"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN துண்டிக்கப்பட்டது"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> வழியாக"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 0e4c779..4a9144b 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"ไมโครโฟนเปิดใช้งานอยู่"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s เข้าถึงไมโครโฟนแล้ว"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"เชื่อมต่อ VPN แล้ว"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ยกเลิกการเชื่อมต่อ VPN แล้ว"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ผ่าน <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0fd8b3e..b8cdef1 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -28,15 +28,15 @@
     <string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
     <string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
     <string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pangtipid sa Baterya."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pantipid ng Baterya."</string>
     <string name="invalid_charger" msgid="4370074072117767416">"Hindi makapag-charge sa pamamagitan ng USB. Gamitin ang charger na kasama ng iyong device."</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Hindi makapag-charge sa pamamagitan ng USB"</string>
     <string name="invalid_charger_text" msgid="2339310107232691577">"Gamitin ang charger na kasama ng iyong device"</string>
     <string name="battery_low_why" msgid="2056750982959359863">"Mga Setting"</string>
-    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pangtipid sa Baterya?"</string>
-    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pangtipid sa Baterya"</string>
+    <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pantipid ng Baterya?"</string>
+    <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pantipid ng Baterya"</string>
     <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"I-on"</string>
-    <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pantipid ng Baterya"</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"I-auto rotate ang screen"</string>
@@ -423,7 +423,7 @@
     <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Mao-on sa ganap na <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Madilim na tema"</string>
-    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pangtipid sa Baterya"</string>
+    <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pantipid ng Baterya"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Mao-on sa sunset"</string>
     <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
     <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -501,9 +501,9 @@
     <string name="user_remove_user_title" msgid="9124124694835811874">"Gusto mo bang alisin ang user?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Made-delete ang lahat ng app at data ng user na ito."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Alisin"</string>
-    <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pantipid ng Baterya"</string>
     <string name="battery_saver_notification_text" msgid="2617841636449016951">"Binabawasan ang performance at data sa background"</string>
-    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pangtipid sa Baterya"</string>
+    <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pantipid ng Baterya"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Magkakaroon ng access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Magsimulang mag-record o mag-cast?"</string>
@@ -777,8 +777,8 @@
       <item quantity="other">%d na minuto</item>
     </plurals>
     <string name="battery_panel_title" msgid="5931157246673665963">"Paggamit ng baterya"</string>
-    <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
-    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pangtipid sa Baterya"</string>
+    <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pantipid ng Baterya kapag nagcha-charge"</string>
+    <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pantipid ng Baterya"</string>
     <string name="battery_detail_switch_summary" msgid="3668748557848025990">"Binabawasan ang performance at data sa background"</string>
     <string name="keyboard_key_button_template" msgid="8005673627272051429">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -965,11 +965,11 @@
     <string name="slice_permission_checkbox" msgid="4242888137592298523">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na ipakita ang mga slice mula sa anumang app"</string>
     <string name="slice_permission_allow" msgid="6340449521277951123">"Payagan"</string>
     <string name="slice_permission_deny" msgid="6870256451658176895">"Tanggihan"</string>
-    <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pangtipid sa Baterya"</string>
+    <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pantipid ng Baterya"</string>
     <string name="auto_saver_text" msgid="3214960308353838764">"I-on kapag malamang na maubos ang baterya"</string>
     <string name="no_auto_saver_action" msgid="7467924389609773835">"Hindi, salamat na lang"</string>
-    <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pangtipid sa Baterya"</string>
-    <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pangtipid sa Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
+    <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pantipid ng Baterya"</string>
+    <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pantipid ng Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
     <string name="open_saver_setting_action" msgid="2111461909782935190">"Mga Setting"</string>
     <string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
     <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 9a66344..3489503 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Aktibo ang Mikropono"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Na-access ng %1$s ang iyong mikropono"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Nakakonekta ang VPN"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Nakadiskonekta ang VPN"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Sa pamamagitan ng <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6d4023a..74666b2 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tekrar ekran görüntüsü almayı deneyin"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Düzenle"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekran görüntüsünü düzenle"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Kaydır"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Kayan ekran görüntüsü"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran görüntüsünü kapat"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran görüntüsü önizlemesi"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index c7033f1..bfb1ae2 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon Etkin"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofonunuza erişti"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN bağlandı"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN bağlantısı kesildi"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> yoluyla"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7a78c3d..2737ce8 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Спробуйте зробити знімок екрана ще раз"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Не вдалося зберегти знімок екрана через обмежений обсяг пам’яті"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Редагувати"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Редагувати знімок екрана"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Прокрутити"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Прокрутити знімок екрана"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрити знімок екрана"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Перегляд знімка екрана"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Відеозапис екрана"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index dbf5955..4a4cac9 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Мікрофон активовано"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"Додаток %1$s отримав доступ до вашого мікрофона"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"Мережу VPN під\'єднано"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Мережу VPN від\'єднано"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ac05019..7488323 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوبارہ اسکرین شاٹ لینے کی کوشش کریں"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"اسٹوریج کی محدود جگہ کی وجہ سے اسکرین شاٹ کو محفوظ نہیں کیا جا سکتا"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"ترمیم کریں"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"اسکرین شاٹ میں ترمیم کریں"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"اسکرول کریں"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"اسکرین شاٹ پر اسکرول کریں"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"اسکرین شاٹ برخاست کریں"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"اسکرین شاٹ کا پیش منظر"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"سکرین ریکارڈر"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings_tv.xml b/packages/SystemUI/res/values-uz/strings_tv.xml
index 3cab93d..fc4ecd3 100644
--- a/packages/SystemUI/res/values-uz/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Mikrofon faol"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofondan foydalandi"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ulandi"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN uzildi"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> orqali"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index df09689..98697fd 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Micrô đang hoạt động"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s đang dùng micrô của bạn"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN đã được kết nối"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN đã bị ngắt kết nối"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Thông qua <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 5b6bb89..68630bb 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"请再次尝试截屏"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"由于存储空间有限,无法保存屏幕截图"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"此应用或您所在的单位不允许进行屏幕截图"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"编辑"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"编辑屏幕截图"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"滚动"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"滚动抓取长截图"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"关闭屏幕截图"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"屏幕截图预览"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index 3d07311..169d98a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"麦克风处于启用状态"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s访问过您的麦克风"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已连接"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 已断开连接"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"通过“<xliff:g id="VPN_APP">%1$s</xliff:g>”"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 9c065fb..ddf60fb 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -88,8 +88,8 @@
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"應用程式或您的機構不允許擷取螢幕畫面"</string>
     <string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
-    <string name="screenshot_scroll_label" msgid="7682877978685434621">"拍攝長截圖"</string>
-    <string name="screenshot_scroll_description" msgid="7855773867093272175">"以捲動畫面的方式拍攝長截圖"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"捲動"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"整頁截圖"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index b0baf19..8581851 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"麥克風已啟用"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取您的麥克風"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已連線"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 已中斷連線"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過 <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index 64e0538c..fcb16b7 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"麥克風已開啟"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取你的麥克風"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已連線"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 連線已中斷"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1a10121..ca87d97 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -86,16 +86,11 @@
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zama ukuthatha isithombe-skrini futhi"</string>
     <string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Ayikwazi ukulondoloza isithombe-skrini ngenxa yesikhala sesitoreji esikhawulelwe"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho"</string>
-    <!-- no translation found for screenshot_edit_label (8754981973544133050) -->
-    <skip />
-    <!-- no translation found for screenshot_edit_description (3333092254706788906) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_label (7682877978685434621) -->
-    <skip />
-    <!-- no translation found for screenshot_scroll_description (7855773867093272175) -->
-    <skip />
-    <!-- no translation found for screenshot_dismiss_description (4702341245899508786) -->
-    <skip />
+    <string name="screenshot_edit_label" msgid="8754981973544133050">"Hlela"</string>
+    <string name="screenshot_edit_description" msgid="3333092254706788906">"Hlela isithombe-skrini"</string>
+    <string name="screenshot_scroll_label" msgid="7682877978685434621">"Skrola"</string>
+    <string name="screenshot_scroll_description" msgid="7855773867093272175">"Isithombe seskrini sokuskrola"</string>
+    <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cashisa isithombe-skrini"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Ukubuka kuqala isithombe-skrini"</string>
     <string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index 46ff929..5cb6c1d1 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -21,10 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="mic_active" msgid="5766614241012047024">"Imakrofoni iyasebenza"</string>
     <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ifinyelele imakrofoni yakho"</string>
-    <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
-    <skip />
-    <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
-    <skip />
-    <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
-    <skip />
+    <string name="notification_vpn_connected" msgid="3891023882833274730">"I-VPN ixhunyiwe"</string>
+    <string name="notification_vpn_disconnected" msgid="7150747626448044843">"I-VPN inqanyuliwe"</string>
+    <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nge-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a2e9f39..4a5e890 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -149,7 +149,7 @@
     <dimen name="notification_max_heads_up_height_increased">188dp</dimen>
 
     <!-- Side padding on the lockscreen on the side of notifications -->
-    <dimen name="notification_side_paddings">4dp</dimen>
+    <dimen name="notification_side_paddings">16dp</dimen>
 
     <!-- padding between the heads up and the statusbar -->
     <dimen name="heads_up_status_bar_padding">8dp</dimen>
@@ -170,6 +170,9 @@
     <!-- Minimum height of a notification to be interactable -->
     <dimen name="notification_min_interaction_height">40dp</dimen>
 
+    <!-- New radius for notifications. -->
+    <dimen name="notification_corner_radius">20dp</dimen>
+
     <!-- the padding of the shelf icon container -->
     <dimen name="shelf_icon_container_padding">13dp</dimen>
 
@@ -609,7 +612,7 @@
     <dimen name="z_distance_between_notifications">0.5dp</dimen>
 
     <!-- The height of the divider between the individual notifications. -->
-    <dimen name="notification_divider_height">0.5dp</dimen>
+    <dimen name="notification_divider_height">4dp</dimen>
 
     <!-- The corner radius of the shadow behind the notification. -->
     <dimen name="notification_shadow_radius">0dp</dimen>
@@ -619,9 +622,7 @@
 
     <!-- The height of the divider between the individual notifications in a notification
          group. -->
-    <dimen name="notification_children_container_divider_height">
-        @dimen/notification_divider_height
-    </dimen>
+    <dimen name="notification_children_container_divider_height">0.5dp</dimen>
 
     <!-- The horizontal margin of the content in the notification shade -->
     <dimen name="notification_shade_content_margin_horizontal">16dp</dimen>
@@ -634,9 +635,6 @@
     <!-- The height of a notification header -->
     <dimen name="notification_header_height">53dp</dimen>
 
-    <!-- The height of the divider between the individual notifications when the notification wants it to be increased. This is currently the case for notification groups -->
-    <dimen name="notification_divider_height_increased">6dp</dimen>
-
     <!-- The height of the gap between adjacent notification sections. -->
     <dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index 27e4c85..bf23a49 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -36,6 +36,7 @@
 
 /**
  * Manages the input consumer that allows the SystemUI to directly receive input.
+ * TODO: Refactor this for the gesture nav case
  */
 public class InputConsumerController {
 
@@ -99,14 +100,6 @@
     }
 
     /**
-     * @return A controller for the pip input consumer.
-     */
-    public static InputConsumerController getPipInputConsumer() {
-        return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
-                INPUT_CONSUMER_PIP);
-    }
-
-    /**
      * @return A controller for the recents animation input consumer.
      */
     public static InputConsumerController getRecentsAnimationInputConsumer() {
@@ -155,7 +148,6 @@
         if (mInputEventReceiver == null) {
             final InputChannel inputChannel = new InputChannel();
             try {
-                // TODO(b/113087003): Support Picture-in-picture in multi-display.
                 mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
                 mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
             } catch (RemoteException e) {
@@ -175,7 +167,6 @@
     public void unregisterInputConsumer() {
         if (mInputEventReceiver != null) {
             try {
-                // TODO(b/113087003): Support Picture-in-picture in multi-display.
                 mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to destroy input consumer", e);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 17bb40e..f073ced 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -118,10 +118,7 @@
                     .setBubbles(Optional.ofNullable(null))
                     .setShellDump(Optional.ofNullable(null));
         }
-        mSysUIComponent = builder
-                .setInputConsumerController(mWMComponent.getInputConsumerController())
-                .setShellTaskOrganizer(mWMComponent.getShellTaskOrganizer())
-                .build();
+        mSysUIComponent = builder.build();
         if (initializeComponents) {
             mSysUIComponent.init();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 3aa4626..b3e6033 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -79,6 +79,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.util.leak.LeakDetector;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.util.Optional;
@@ -208,6 +209,7 @@
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue,
+            Optional<Pip> pipOptional,
             Optional<SplitScreen> splitScreenOptional,
             Optional<Recents> recentsOptional,
             Lazy<StatusBar> statusBarLazy,
@@ -230,6 +232,7 @@
                 sysUiFlagsContainer,
                 broadcastDispatcher,
                 commandQueue,
+                pipOptional,
                 splitScreenOptional,
                 recentsOptional,
                 statusBarLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index b94a68b..54aeab5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,11 +22,9 @@
 import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.util.InjectionInflationController;
 import com.android.wm.shell.ShellDump;
-import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
@@ -68,12 +66,6 @@
         Builder setBubbles(Optional<Bubbles> b);
 
         @BindsInstance
-        Builder setInputConsumerController(InputConsumerController i);
-
-        @BindsInstance
-        Builder setShellTaskOrganizer(ShellTaskOrganizer s);
-
-        @BindsInstance
         Builder setShellDump(Optional<ShellDump> shellDump);
 
         SysUIComponent build();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 8f3d8ea..9154ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,11 +16,9 @@
 
 package com.android.systemui.dagger;
 
-import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.wmshell.WMShellModule;
 import com.android.wm.shell.ShellDump;
 import com.android.wm.shell.ShellInit;
-import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
@@ -60,14 +58,6 @@
     @WMSingleton
     Optional<ShellDump> getShellDump();
 
-    // TODO(b/162923491): Refactor this out so Pip doesn't need to inject this
-    @WMSingleton
-    InputConsumerController getInputConsumerController();
-
-    // TODO(b/162923491): To be removed once Bubbles migrates over to the Shell
-    @WMSingleton
-    ShellTaskOrganizer getShellTaskOrganizer();
-
     // TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
     //                    depending on the threading mechanism we go with
     @WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2705f07..4c68312 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1007,7 +1007,7 @@
         intent.putExtra("seq", mDelayedShowingSequence);
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         PendingIntent sender = PendingIntent.getBroadcast(mContext,
-                0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+                0, intent, PendingIntent.FLAG_CANCEL_CURRENT |  PendingIntent.FLAG_IMMUTABLE);
         mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
         if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
                          + mDelayedShowingSequence);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4e0df21..b6ca77b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -136,6 +136,7 @@
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.io.PrintWriter;
@@ -179,6 +180,7 @@
     private final NavigationModeController mNavigationModeController;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
+    private final Optional<Pip> mPipOptional;
     private final Optional<SplitScreen> mSplitScreenOptional;
     private final Optional<Recents> mRecentsOptional;
     private final SystemActions mSystemActions;
@@ -406,6 +408,7 @@
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue,
+            Optional<Pip> pipOptional,
             Optional<SplitScreen> splitScreenOptional,
             Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
             ShadeController shadeController,
@@ -430,6 +433,7 @@
         mNavBarMode = navigationModeController.addListener(this);
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
+        mPipOptional = pipOptional;
         mSplitScreenOptional = splitScreenOptional;
         mRecentsOptional = recentsOptional;
         mSystemActions = systemActions;
@@ -529,6 +533,7 @@
         mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
         mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
         mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
+        mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
 
         prepareNavigationBarView();
         checkNavBarModes();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 339e504..f7f3400 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -64,6 +64,7 @@
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.io.FileDescriptor;
@@ -96,6 +97,7 @@
     private final SysUiState mSysUiFlagsContainer;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
+    private final Optional<Pip> mPipOptional;
     private final Optional<SplitScreen> mSplitScreenOptional;
     private final Optional<Recents> mRecentsOptional;
     private final Lazy<StatusBar> mStatusBarLazy;
@@ -130,6 +132,7 @@
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue,
+            Optional<Pip> pipOptional,
             Optional<SplitScreen> splitScreenOptional,
             Optional<Recents> recentsOptional,
             Lazy<StatusBar> statusBarLazy,
@@ -152,6 +155,7 @@
         mSysUiFlagsContainer = sysUiFlagsContainer;
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
+        mPipOptional = pipOptional;
         mSplitScreenOptional = splitScreenOptional;
         mRecentsOptional = recentsOptional;
         mStatusBarLazy = statusBarLazy;
@@ -278,6 +282,7 @@
                 mSysUiFlagsContainer,
                 mBroadcastDispatcher,
                 mCommandQueue,
+                mPipOptional,
                 mSplitScreenOptional,
                 mRecentsOptional,
                 mStatusBarLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 37c79cc..4c3ac40 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.phone.LightBarTransitionsController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.io.PrintWriter;
@@ -1292,6 +1293,10 @@
         splitScreen.registerInSplitScreenListener(mDockedListener);
     }
 
+    void registerPipExclusionBoundsChangeListener(Pip pip) {
+        pip.setPipExclusionBoundsChangeListener(mPipListener);
+    }
+
     private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
         pw.print("      " + caption + ": ");
         if (button == null) {
@@ -1312,4 +1317,8 @@
         mDockedStackExists = exists;
         updateRecentsIcon();
     });
+
+    private final Consumer<Rect> mPipListener = bounds -> post(() -> {
+        mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
+    });
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index f9982d0..6dee63c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -24,6 +24,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
@@ -160,6 +161,7 @@
 
     private final Executor mMainExecutor;
 
+    private final Rect mPipExcludedBounds = new Rect();
     private final Region mExcludeRegion = new Region();
     private final Region mUnrestrictedExcludeRegion = new Region();
 
@@ -456,6 +458,13 @@
         return mIsEnabled && mIsBackGestureAllowed;
     }
 
+    /**
+     * Update the PiP bounds, used for exclusion calculation.
+     */
+    public void setPipStashExclusionBounds(Rect bounds) {
+        mPipExcludedBounds.set(bounds);
+    }
+
     private WindowManager.LayoutParams createLayoutParams() {
         Resources resources = mContext.getResources();
         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
@@ -556,6 +565,11 @@
             return false;
         }
 
+        // If the point is inside the PiP excluded bounds, then drop it.
+        if (mPipExcludedBounds.contains(x, y)) {
+            return false;
+        }
+
         if (mUseMLModel &&  (results = getBackGesturePredictionsCategory(x, y)) != -1) {
             withinRange = results == 1 ? true : false;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 7fe88b9..07a5839 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -221,6 +221,8 @@
                 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
         mWindowLayoutParams.token = mWindowToken;
+        // This is needed to let touches pass through outside the touchable areas
+        mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
         mDisplayMetrics = new DisplayMetrics();
         mDisplay.getRealMetrics(mDisplayMetrics);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a011d36..2253b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -331,7 +331,6 @@
     private OnUserInteractionCallback mOnUserInteractionCallback;
     private NotificationGutsManager mNotificationGutsManager;
     private boolean mIsLowPriority;
-    private boolean mIsColorized;
     private boolean mUseIncreasedCollapsedHeight;
     private boolean mUseIncreasedHeadsUpHeight;
     private float mTranslationWhenRemoved;
@@ -541,7 +540,6 @@
         for (NotificationContentView l : mLayouts) {
             l.onNotificationUpdated(mEntry);
         }
-        mIsColorized = mEntry.getSbn().getNotification().isColorized();
         mShowingPublicInitialized = false;
         updateNotificationColor();
         if (mMenuRow != null) {
@@ -1624,8 +1622,6 @@
                 R.dimen.notification_max_heads_up_height_increased);
 
         Resources res = getResources();
-        mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
-                R.dimen.notification_divider_height_increased);
         mEnableNonGroupedNotificationExpand =
                 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
         mShowGroupBackgroundWhenExpanded =
@@ -2844,24 +2840,6 @@
     }
 
     @Override
-    public float getIncreasedPaddingAmount() {
-        if (mIsSummaryWithChildren) {
-            if (isGroupExpanded()) {
-                return 1.0f;
-            } else if (isUserLocked()) {
-                return mChildrenContainer.getIncreasedPaddingAmount();
-            }
-        } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
-            return -1.0f;
-        }
-        return 0.0f;
-    }
-
-    private boolean isColorized() {
-        return mIsColorized && mBgTint != NO_COLOR;
-    }
-
-    @Override
     protected boolean disallowSingleClick(MotionEvent event) {
         if (areGutsExposed()) {
             return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index bb78f61..2ff43d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -239,8 +239,7 @@
         mOutlineRadius = res.getDimension(R.dimen.notification_shadow_radius);
         mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
         if (!mAlwaysRoundBothCorners) {
-            mOutlineRadius = res.getDimensionPixelSize(
-                    Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+            mOutlineRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
         }
         setClipToOutline(mAlwaysRoundBothCorners);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ccfd8a3..73e0804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -499,15 +499,6 @@
         return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
     }
 
-    /**
-     * @return an amount between -1 and 1 of increased padding that this child needs. 1 means it
-     * needs a full increased padding while -1 means it needs no padding at all. For 0.0f the normal
-     * padding is applied.
-     */
-    public float getIncreasedPaddingAmount() {
-        return 0.0f;
-    }
-
     public boolean mustStayOnScreen() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 00bccfc..b04f94c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1271,13 +1271,6 @@
         }
     }
 
-    public float getIncreasedPaddingAmount() {
-        if (showingAsLowPriority()) {
-            return 0.0f;
-        }
-        return getGroupExpandFraction();
-    }
-
     @VisibleForTesting
     public boolean isUserLocked() {
         return mUserLocked;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2a2a0b1..fbcfef3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -198,7 +198,6 @@
     private int mIntrinsicContentHeight;
     private int mCollapsedSize;
     private int mPaddingBetweenElements;
-    private int mIncreasedPaddingBetweenElements;
     private int mMaxTopPadding;
     private int mTopPadding;
     private int mBottomMargin;
@@ -883,8 +882,6 @@
         mAmbientState.reload(context);
         mPaddingBetweenElements = Math.max(1,
                 res.getDimensionPixelSize(R.dimen.notification_divider_height));
-        mIncreasedPaddingBetweenElements =
-                res.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
         mMinTopOverScrollToEscape = res.getDimensionPixelSize(
                 R.dimen.min_top_overscroll_to_qs);
         mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
@@ -892,15 +889,13 @@
         mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
         mMinInteractionHeight = res.getDimensionPixelSize(
                 R.dimen.notification_min_interaction_height);
-        mCornerRadius = res.getDimensionPixelSize(
-                Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+        mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
         mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
                 R.dimen.heads_up_status_bar_padding);
     }
 
     void updateCornerRadius() {
-        int newRadius = getResources().getDimensionPixelSize(
-                Utils.getThemeAttr(getContext(), android.R.attr.dialogCornerRadius));
+        int newRadius = getResources().getDimensionPixelSize(R.dimen.notification_corner_radius);
         if (mCornerRadius != newRadius) {
             mCornerRadius = newRadius;
             invalidate();
@@ -1101,11 +1096,8 @@
             for (int i = 0; i < getChildCount(); i++) {
                 ExpandableView child = (ExpandableView) getChildAt(i);
                 if (mChildrenToAddAnimated.contains(child)) {
-                    int startingPosition = getPositionInLinearLayout(child);
-                    float increasedPaddingAmount = child.getIncreasedPaddingAmount();
-                    int padding = increasedPaddingAmount == 1.0f ? mIncreasedPaddingBetweenElements
-                            : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
-                    int childHeight = getIntrinsicHeight(child) + padding;
+                    final int startingPosition = getPositionInLinearLayout(child);
+                    final int childHeight = getIntrinsicHeight(child) + mPaddingBetweenElements;
                     if (startingPosition < mOwnScrollY) {
                         // This child starts off screen, so let's keep it offscreen to keep the
                         // others visible
@@ -2299,7 +2291,6 @@
     private void updateContentHeight() {
         int height = 0;
         float previousPaddingRequest = mPaddingBetweenElements;
-        float previousPaddingAmount = 0.0f;
         int numShownItems = 0;
         boolean finish = false;
         int maxDisplayedNotifications = mMaxDisplayedNotifications;
@@ -2318,37 +2309,10 @@
                 } else {
                     viewHeight = expandableView.getIntrinsicHeight();
                 }
-                float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
-                float padding;
-                if (increasedPaddingAmount >= 0.0f) {
-                    padding = (int) NotificationUtils.interpolate(
-                            previousPaddingRequest,
-                            mIncreasedPaddingBetweenElements,
-                            increasedPaddingAmount);
-                    previousPaddingRequest = (int) NotificationUtils.interpolate(
-                            mPaddingBetweenElements,
-                            mIncreasedPaddingBetweenElements,
-                            increasedPaddingAmount);
-                } else {
-                    int ownPadding = (int) NotificationUtils.interpolate(
-                            0,
-                            mPaddingBetweenElements,
-                            1.0f + increasedPaddingAmount);
-                    if (previousPaddingAmount > 0.0f) {
-                        padding = (int) NotificationUtils.interpolate(
-                                ownPadding,
-                                mIncreasedPaddingBetweenElements,
-                                previousPaddingAmount);
-                    } else {
-                        padding = ownPadding;
-                    }
-                    previousPaddingRequest = ownPadding;
-                }
                 if (height != 0) {
-                    height += padding;
+                    height += mPaddingBetweenElements;
                 }
                 height += calculateGapHeight(previousView, expandableView, numShownItems);
-                previousPaddingAmount = increasedPaddingAmount;
                 height += viewHeight;
                 numShownItems++;
                 previousView = expandableView;
@@ -3056,22 +3020,9 @@
             }
             updateOnScrollChange();
         } else {
-            int startingPosition = getPositionInLinearLayout(removedChild);
-            float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
-            int padding;
-            if (increasedPaddingAmount >= 0) {
-                padding = (int) NotificationUtils.interpolate(
-                        mPaddingBetweenElements,
-                        mIncreasedPaddingBetweenElements,
-                        increasedPaddingAmount);
-            } else {
-                padding = (int) NotificationUtils.interpolate(
-                        0,
-                        mPaddingBetweenElements,
-                        1.0f + increasedPaddingAmount);
-            }
-            int childHeight = getIntrinsicHeight(removedChild) + padding;
-            int endPosition = startingPosition + childHeight;
+            final int startingPosition = getPositionInLinearLayout(removedChild);
+            final int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
+            final int endPosition = startingPosition + childHeight;
             if (endPosition <= mOwnScrollY) {
                 // This child is fully scrolled of the top, so we have to deduct its height from the
                 // scrollPosition
@@ -3104,42 +3055,13 @@
             requestedView = requestedRow = childInGroup.getNotificationParent();
         }
         int position = 0;
-        float previousPaddingRequest = mPaddingBetweenElements;
-        float previousPaddingAmount = 0.0f;
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
             boolean notGone = child.getVisibility() != View.GONE;
             if (notGone && !child.hasNoContentHeight()) {
-                float increasedPaddingAmount = child.getIncreasedPaddingAmount();
-                float padding;
-                if (increasedPaddingAmount >= 0.0f) {
-                    padding = (int) NotificationUtils.interpolate(
-                            previousPaddingRequest,
-                            mIncreasedPaddingBetweenElements,
-                            increasedPaddingAmount);
-                    previousPaddingRequest = (int) NotificationUtils.interpolate(
-                            mPaddingBetweenElements,
-                            mIncreasedPaddingBetweenElements,
-                            increasedPaddingAmount);
-                } else {
-                    int ownPadding = (int) NotificationUtils.interpolate(
-                            0,
-                            mPaddingBetweenElements,
-                            1.0f + increasedPaddingAmount);
-                    if (previousPaddingAmount > 0.0f) {
-                        padding = (int) NotificationUtils.interpolate(
-                                ownPadding,
-                                mIncreasedPaddingBetweenElements,
-                                previousPaddingAmount);
-                    } else {
-                        padding = ownPadding;
-                    }
-                    previousPaddingRequest = ownPadding;
-                }
                 if (position != 0) {
-                    position += padding;
+                    position += mPaddingBetweenElements;
                 }
-                previousPaddingAmount = increasedPaddingAmount;
             }
             if (child == requestedView) {
                 if (requestedRow != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index d7a8202..d85baa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -51,7 +51,6 @@
     private final ViewGroup mHostView;
 
     private int mPaddingBetweenElements;
-    private int mIncreasedPaddingBetweenElements;
     private int mGapHeight;
     private int mCollapsedSize;
 
@@ -77,8 +76,6 @@
         Resources res = context.getResources();
         mPaddingBetweenElements = res.getDimensionPixelSize(
                 R.dimen.notification_divider_height);
-        mIncreasedPaddingBetweenElements =
-                res.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
         mCollapsedSize = res.getDimensionPixelSize(R.dimen.notification_min_height);
         mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
         mClipNotificationScrollToTop = res.getBoolean(R.bool.config_clipNotificationScrollToTop);
@@ -240,17 +237,8 @@
         int childCount = hostView.getChildCount();
         state.visibleChildren.clear();
         state.visibleChildren.ensureCapacity(childCount);
-        state.paddingMap.clear();
         int notGoneIndex = 0;
         ExpandableView lastView = null;
-        int firstHiddenIndex = ambientState.isDozing()
-                ? (ambientState.hasPulsingNotifications() ? 1 : 0)
-                : childCount;
-
-        // The goal here is to fill the padding map, by iterating over how much padding each child
-        // needs. The map is thereby reused, by first filling it with the padding amount and when
-        // iterating over it again, it's filled with the actual resolved value.
-
         for (int i = 0; i < childCount; i++) {
             if (ANCHOR_SCROLLING) {
                 if (i == ambientState.getAnchorViewIndex()) {
@@ -262,39 +250,7 @@
                 if (v == ambientState.getShelf()) {
                     continue;
                 }
-                if (i >= firstHiddenIndex) {
-                    // we need normal padding now, to be in sync with what the stack calculates
-                    lastView = null;
-                }
                 notGoneIndex = updateNotGoneIndex(state, notGoneIndex, v);
-                float increasedPadding = v.getIncreasedPaddingAmount();
-                if (increasedPadding != 0.0f) {
-                    state.paddingMap.put(v, increasedPadding);
-                    if (lastView != null) {
-                        Float prevValue = state.paddingMap.get(lastView);
-                        float newValue = getPaddingForValue(increasedPadding);
-                        if (prevValue != null) {
-                            float prevPadding = getPaddingForValue(prevValue);
-                            if (increasedPadding > 0) {
-                                newValue = NotificationUtils.interpolate(
-                                        prevPadding,
-                                        newValue,
-                                        increasedPadding);
-                            } else if (prevValue > 0) {
-                                newValue = NotificationUtils.interpolate(
-                                        newValue,
-                                        prevPadding,
-                                        prevValue);
-                            }
-                        }
-                        state.paddingMap.put(lastView, newValue);
-                    }
-                } else if (lastView != null) {
-
-                    // Let's now resolve the value to an actual padding
-                    float newValue = getPaddingForValue(state.paddingMap.get(lastView));
-                    state.paddingMap.put(lastView, newValue);
-                }
                 if (v instanceof ExpandableNotificationRow) {
                     ExpandableNotificationRow row = (ExpandableNotificationRow) v;
 
@@ -310,7 +266,6 @@
                         }
                     }
                 }
-                lastView = v;
             }
         }
         ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification();
@@ -321,22 +276,6 @@
                 : -1;
     }
 
-    private float getPaddingForValue(Float increasedPadding) {
-        if (increasedPadding == null) {
-            return mPaddingBetweenElements;
-        } else if (increasedPadding >= 0.0f) {
-            return NotificationUtils.interpolate(
-                    mPaddingBetweenElements,
-                    mIncreasedPaddingBetweenElements,
-                    increasedPadding);
-        } else {
-            return NotificationUtils.interpolate(
-                    0,
-                    mPaddingBetweenElements,
-                    1.0f + increasedPadding);
-        }
-    }
-
     private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex,
             ExpandableView v) {
         ExpandableViewState viewState = v.getViewState();
@@ -413,10 +352,10 @@
             currentYPosition += mGapHeight;
         }
 
-        int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
         int childHeight = getMaxAllowedChildHeight(child);
         if (reverse) {
-            childViewState.yTranslation = currentYPosition - (childHeight + paddingAfterChild);
+            childViewState.yTranslation = currentYPosition
+                    - (childHeight + mPaddingBetweenElements);
             if (currentYPosition <= 0) {
                 childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
             }
@@ -453,7 +392,7 @@
                 currentYPosition -= mGapHeight;
             }
         } else {
-            currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
+            currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
             if (currentYPosition <= 0) {
                 childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
             }
@@ -516,11 +455,6 @@
         return needsGapHeight;
     }
 
-    protected int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
-            ExpandableView child) {
-        return algorithmState.getPaddingAfterChild(child);
-    }
-
     private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
@@ -780,21 +714,8 @@
          */
         public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
 
-        /**
-         * The padding after each child measured in pixels.
-         */
-        public final HashMap<ExpandableView, Float> paddingMap = new HashMap<>();
         private int indexOfExpandingNotification;
 
-        public int getPaddingAfterChild(ExpandableView child) {
-            Float padding = paddingMap.get(child);
-            if (padding == null) {
-                // Should only happen for the last view
-                return mPaddingBetweenElements;
-            }
-            return (int) padding.floatValue();
-        }
-
         public int getIndexOfExpandingNotification() {
             return indexOfExpandingNotification;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 5caab6a..694b4a0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -22,6 +22,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsHandler;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -54,6 +55,7 @@
             PipTaskOrganizer pipTaskOrganizer,
             PipMediaController pipMediaController,
             PipNotification pipNotification,
+            TaskStackListenerImpl taskStackListener,
             WindowManagerShellWrapper windowManagerShellWrapper) {
         return Optional.of(
                 new PipController(
@@ -63,6 +65,7 @@
                         pipTaskOrganizer,
                         pipMediaController,
                         pipNotification,
+                        taskStackListener,
                         windowManagerShellWrapper));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 294c749a..f88bedd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -27,6 +27,7 @@
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -57,8 +58,9 @@
             DisplayController displayController, SystemWindows systemWindows,
             DisplayImeController displayImeController, @Main Handler handler,
             TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
         return new SplitScreenController(context, displayController, systemWindows,
-                displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+                displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+                taskStackListener);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f896891..7a24438 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,7 +55,6 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 import com.android.systemui.shared.tracing.ProtoTraceable;
@@ -71,7 +70,6 @@
 import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.protolog.ShellProtoLogImpl;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
@@ -100,9 +98,7 @@
 
     private final CommandQueue mCommandQueue;
     private final ConfigurationController mConfigurationController;
-    private final InputConsumerController mInputConsumerController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private final TaskStackChangeListeners mTaskStackChangeListeners;
     private final NavigationModeController mNavigationModeController;
     private final ScreenLifecycle mScreenLifecycle;
     private final SysUiState mSysUiState;
@@ -120,9 +116,7 @@
     @Inject
     public WMShell(Context context, CommandQueue commandQueue,
             ConfigurationController configurationController,
-            InputConsumerController inputConsumerController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            TaskStackChangeListeners taskStackChangeListeners,
             NavigationModeController navigationModeController,
             ScreenLifecycle screenLifecycle,
             SysUiState sysUiState,
@@ -134,9 +128,7 @@
         super(context);
         mCommandQueue = commandQueue;
         mConfigurationController = configurationController;
-        mInputConsumerController = inputConsumerController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
-        mTaskStackChangeListeners = taskStackChangeListeners;
         mNavigationModeController = navigationModeController;
         mScreenLifecycle = screenLifecycle;
         mSysUiState = sysUiState;
@@ -192,58 +184,6 @@
             }
         });
 
-        // TODO: Move this into the shell
-        // Handle for system task stack changes.
-        mTaskStackChangeListeners.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);
-                        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) ->
@@ -263,39 +203,6 @@
             }
         };
         mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
-
-        mTaskStackChangeListeners.registerTaskStackListener(
-                new TaskStackChangeListener() {
-                    @Override
-                    public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
-                            boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
-                        if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
-                                != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
-                                || !splitScreen.isSplitScreenSupported()) {
-                            return;
-                        }
-
-                        if (splitScreen.isMinimized()) {
-                            splitScreen.onUndockingTask();
-                        }
-                    }
-
-                    @Override
-                    public void onActivityForcedResizable(String packageName, int taskId,
-                            int reason) {
-                        splitScreen.onActivityForcedResizable(packageName, taskId, reason);
-                    }
-
-                    @Override
-                    public void onActivityDismissingDockedStack() {
-                        splitScreen.onActivityDismissingSplitScreen();
-                    }
-
-                    @Override
-                    public void onActivityLaunchOnSecondaryDisplayFailed() {
-                        splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
-                    }
-                });
     }
 
     @VisibleForTesting
@@ -375,21 +282,6 @@
                 }
             }
         });
-
-        mTaskStackChangeListeners.registerTaskStackListener(
-                new TaskStackChangeListener() {
-                    @Override
-                    public void onTaskCreated(int taskId, ComponentName componentName) {
-                        oneHanded.stopOneHanded(
-                                OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
-                    }
-
-                    @Override
-                    public void onTaskMovedToFront(int taskId) {
-                        oneHanded.stopOneHanded(
-                                OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
-                    }
-                });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index bdca503..6546ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -116,12 +117,6 @@
 
     @WMSingleton
     @Provides
-    static InputConsumerController provideInputConsumerController() {
-        return InputConsumerController.getPipInputConsumer();
-    }
-
-    @WMSingleton
-    @Provides
     static FloatingContentCoordinator provideFloatingContentCoordinator() {
         return new FloatingContentCoordinator();
     }
@@ -181,6 +176,12 @@
                 mainExecutor, AnimationThread.instance().getExecutor());
     }
 
+    @WMSingleton
+    @Provides
+    static TaskStackListenerImpl providerTaskStackListenerImpl(@Main Handler handler) {
+        return new TaskStackListenerImpl(handler);
+    }
+
     @BindsOptionalOf
     abstract SplitScreen optionalSplitScreen();
 
@@ -203,8 +204,9 @@
     @WMSingleton
     @Provides
     static Optional<OneHanded> provideOneHandedController(Context context,
-            DisplayController displayController) {
-        return Optional.ofNullable(OneHandedController.create(context, displayController));
+            DisplayController displayController, TaskStackListenerImpl taskStackListener) {
+        return Optional.ofNullable(OneHandedController.create(context, displayController,
+                taskStackListener));
     }
 
     @WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 25ca7ad..1cdec27 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -30,6 +30,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsHandler;
@@ -72,9 +73,10 @@
             DisplayController displayController, SystemWindows systemWindows,
             DisplayImeController displayImeController, @Main Handler handler,
             TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
         return new SplitScreenController(context, displayController, systemWindows,
-                displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+                displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+                taskStackListener);
     }
 
     @WMSingleton
@@ -84,11 +86,11 @@
             PipBoundsState pipBoundsState, PipMediaController pipMediaController,
             PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
             PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
-            ShellExecutor mainExecutor) {
+            TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(context, displayController,
                 pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController,
                 pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
-                windowManagerShellWrapper, mainExecutor));
+                windowManagerShellWrapper, taskStackListener, mainExecutor));
     }
 
     @WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index ad5f987..32c360f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -59,6 +59,7 @@
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import org.junit.After;
@@ -96,6 +97,7 @@
                         mock(SysUiState.class),
                         mock(BroadcastDispatcher.class),
                         mock(CommandQueue.class),
+                        Optional.of(mock(Pip.class)),
                         Optional.of(mock(SplitScreen.class)),
                         Optional.of(mock(Recents.class)),
                         () -> mock(StatusBar.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index f308e9e..57eac74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -76,6 +76,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import org.junit.Before;
@@ -223,6 +224,7 @@
                 mMockSysUiState,
                 mBroadcastDispatcher,
                 mCommandQueue,
+                Optional.of(mock(Pip.class)),
                 Optional.of(mock(SplitScreen.class)),
                 Optional.of(mock(Recents.class)),
                 () -> mock(StatusBar.class),
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 d0bf281..6a303a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -62,7 +62,6 @@
     @Mock CommandQueue mCommandQueue;
     @Mock ConfigurationController mConfigurationController;
     @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    @Mock TaskStackChangeListeners mTaskStackChangeListeners;
     @Mock InputConsumerController mMockInputConsumerController;
     @Mock NavigationModeController mNavigationModeController;
     @Mock ScreenLifecycle mScreenLifecycle;
@@ -77,13 +76,11 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mInputConsumerController = InputConsumerController.getPipInputConsumer();
 
         mWMShell = new WMShell(mContext, mCommandQueue, mConfigurationController,
-                mInputConsumerController, mKeyguardUpdateMonitor, mTaskStackChangeListeners,
-                mNavigationModeController, mScreenLifecycle, mSysUiState, Optional.of(mPip),
-                Optional.of(mSplitScreen), Optional.of(mOneHanded), mProtoTracer,
-                Optional.of(mShellDump));
+                mKeyguardUpdateMonitor, mNavigationModeController,
+                mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
+                Optional.of(mOneHanded), mProtoTracer, Optional.of(mShellDump));
 
         when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
     }
@@ -100,8 +97,6 @@
         mWMShell.initSplitScreen(mSplitScreen);
 
         verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
-        verify(mTaskStackChangeListeners).registerTaskStackListener(
-                any(TaskStackChangeListener.class));
     }
 
     @Test
@@ -113,8 +108,6 @@
         verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
         verify(mNavigationModeController).addListener(
                 any(NavigationModeController.ModeChangedListener.class));
-        verify(mTaskStackChangeListeners).registerTaskStackListener(
-                any(TaskStackChangeListener.class));
 
         verify(mOneHanded).registerGestureCallback(any(
                 OneHandedGestureHandler.OneHandedGestureEventCallback.class));
diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml
index a949fae..9d60ff4 100644
--- a/packages/VpnDialogs/res/values-my/strings.xml
+++ b/packages/VpnDialogs/res/values-my/strings.xml
@@ -30,7 +30,7 @@
     <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
     <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ဆက်တင်များ ပြောင်းရန်"</string>
     <string name="configure" msgid="4905518375574791375">"ပုံပေါ်စေသည်"</string>
-    <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
+    <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်ခြင်းရပ်ရန်"</string>
     <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string>
     <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string>
 </resources>
diff --git a/services/core/Android.bp b/services/core/Android.bp
index ff47a83b..fb3c61b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -110,6 +110,7 @@
         "android.hardware.tv.cec-V1.0-java",
         "android.hardware.weaver-V1.0-java",
         "android.hardware.biometrics.face-V1.1-java",
+        "android.hardware.biometrics.face-java",
         "android.hardware.biometrics.fingerprint-V2.3-java",
         "android.hardware.biometrics.fingerprint-java",
         "android.hardware.oemlock-V1.0-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d613427..8b6007c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6443,8 +6443,8 @@
                 && !nai.networkAgentConfig.allowBypass
                 && nc.getOwnerUid() != Process.SYSTEM_UID
                 && lp.getInterfaceName() != null
-                && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
-                && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
+                && (lp.hasIpv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
+                && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
     }
 
     private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
diff --git a/services/core/java/com/android/server/ContextHubSystemService.java b/services/core/java/com/android/server/ContextHubSystemService.java
index c6853a5..a353519 100644
--- a/services/core/java/com/android/server/ContextHubSystemService.java
+++ b/services/core/java/com/android/server/ContextHubSystemService.java
@@ -20,7 +20,7 @@
 import android.util.Log;
 
 import com.android.internal.util.ConcurrentUtils;
-import com.android.server.location.ContextHubService;
+import com.android.server.location.contexthub.ContextHubService;
 
 import java.util.concurrent.Future;
 
diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java
index b0132d3..a2a7dd3 100644
--- a/services/core/java/com/android/server/CountryDetectorService.java
+++ b/services/core/java/com/android/server/CountryDetectorService.java
@@ -33,8 +33,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
-import com.android.server.location.ComprehensiveCountryDetector;
-import com.android.server.location.CountryDetectorBase;
+import com.android.server.location.countrydetector.ComprehensiveCountryDetector;
+import com.android.server.location.countrydetector.CountryDetectorBase;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -43,10 +43,9 @@
 
 /**
  * This class detects the country that the user is in. The default country detection is made through
- * {@link com.android.server.location.ComprehensiveCountryDetector}. It is possible to overlay the
- * detection algorithm by overlaying the attribute R.string.config_customCountryDetector with the
- * custom class name to use instead. The custom class must extend
- * {@link com.android.server.location.CountryDetectorBase}
+ * {@link ComprehensiveCountryDetector}. It is possible to overlay the detection algorithm by
+ * overlaying the attribute R.string.config_customCountryDetector with the custom class name to use
+ * instead. The custom class must extend {@link CountryDetectorBase}
  *
  * @hide
  */
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 74fba04..63fba25a 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -29,11 +29,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.res.Resources;
-import android.database.ContentObserver;
 import android.hardware.input.InputManager;
 import android.hardware.vibrator.IVibrator;
-import android.hardware.vibrator.V1_0.EffectStrength;
-import android.media.AudioManager;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.ExternalVibration;
@@ -56,14 +53,10 @@
 import android.os.ShellCommand;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.WorkSource;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.util.DebugUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
@@ -74,6 +67,8 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.vibrator.VibrationScaler;
+import com.android.server.vibrator.VibrationSettings;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -97,22 +92,6 @@
 
     private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
 
-    // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
-    // and the default intensity for that type of vibration (i.e. current - default).
-    private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
-    private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
-    private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
-    private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
-    private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
-    private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
-
-    // Scale factors for each level.
-    private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
-    private static final float SCALE_FACTOR_LOW = 0.8f;
-    private static final float SCALE_FACTOR_NONE = 1f;
-    private static final float SCALE_FACTOR_HIGH = 1.2f;
-    private static final float SCALE_FACTOR_VERY_HIGH = 1.4f;
-
     // Default vibration attributes. Used when vibration is requested without attributes
     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
             new VibrationAttributes.Builder().build();
@@ -120,11 +99,6 @@
     // Used to generate globally unique vibration ids.
     private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
 
-    // A mapping from the intensity adjustment to the scaling to apply, where the intensity
-    // adjustment is defined as the delta between the default intensity level and the user selected
-    // intensity level. It's important that we apply the scaling on the delta between the two so
-    // that the default intensity level applies no scaling to application provided effects.
-    private final SparseArray<ScaleLevel> mScaleLevels;
     private final LinkedList<VibrationInfo> mPreviousRingVibrations;
     private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
     private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
@@ -149,8 +123,8 @@
     private final String mSystemUiPackage;
     private PowerManagerInternal mPowerManagerInternal;
     private InputManager mIm;
-    private Vibrator mVibrator;
-    private SettingsObserver mSettingObserver;
+    private VibrationSettings mVibrationSettings;
+    private VibrationScaler mVibrationScaler;
 
     private final NativeWrapper mNativeWrapper;
     private volatile VibrateWaveformThread mThread;
@@ -172,9 +146,6 @@
     @GuardedBy("mLock")
     private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
             new RemoteCallbackList<>();
-    private int mHapticFeedbackIntensity;
-    private int mNotificationIntensity;
-    private int mRingIntensity;
     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
 
     static native long vibratorInit(OnCompleteListener listener);
@@ -343,7 +314,7 @@
 
         private ExternalVibrationHolder(ExternalVibration externalVibration) {
             this.externalVibration = externalVibration;
-            this.scale = SCALE_NONE;
+            this.scale = IExternalVibratorService.SCALE_NONE;
             mStartTimeDebug = System.currentTimeMillis();
             mStatus = VibrationInfo.Status.RUNNING;
         }
@@ -518,20 +489,6 @@
         }
     }
 
-    /** Represents the scale that must be applied to a vibration effect intensity. */
-    private static final class ScaleLevel {
-        public final float factor;
-
-        ScaleLevel(float factor) {
-            this.factor = factor;
-        }
-
-        @Override
-        public String toString() {
-            return "ScaleLevel{factor=" + factor + "}";
-        }
-    }
-
     VibratorService(Context context) {
         this(context, new Injector());
     }
@@ -599,13 +556,6 @@
         mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
 
-        mScaleLevels = new SparseArray<>();
-        mScaleLevels.put(SCALE_VERY_LOW, new ScaleLevel(SCALE_FACTOR_VERY_LOW));
-        mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_FACTOR_LOW));
-        mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_FACTOR_NONE));
-        mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
-        mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
-
         injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
     }
 
@@ -628,8 +578,8 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
         try {
             mIm = mContext.getSystemService(InputManager.class);
-            mVibrator = mContext.getSystemService(Vibrator.class);
-            mSettingObserver = new SettingsObserver(mH);
+            mVibrationSettings = new VibrationSettings(mContext, mH);
+            mVibrationScaler = new VibrationScaler(mContext, mVibrationSettings);
 
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
             mPowerManagerInternal.registerLowPowerModeObserver(
@@ -645,25 +595,7 @@
                         }
             });
 
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
-                    true, mSettingObserver, UserHandle.USER_ALL);
-
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
-                    true, mSettingObserver, UserHandle.USER_ALL);
-
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
-                    true, mSettingObserver, UserHandle.USER_ALL);
-
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
-                    true, mSettingObserver, UserHandle.USER_ALL);
-
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
-                    true, mSettingObserver, UserHandle.USER_ALL);
+            mVibrationSettings.addListener(this::updateVibrators);
 
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
@@ -686,17 +618,6 @@
         }
     }
 
-    private final class SettingsObserver extends ContentObserver {
-        public SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean SelfChange) {
-            updateVibrators();
-        }
-    }
-
     /** Callback for when vibration is complete, to be called by native. */
     @VisibleForTesting
     public void onVibrationComplete(long vibrationId) {
@@ -1118,11 +1039,10 @@
     private void startVibrationLocked(final Vibration vib) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
         try {
-            final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
-            if (!shouldVibrate(vib, intensity)) {
+            if (!shouldVibrate(vib)) {
                 return;
             }
-            applyVibrationIntensityScalingLocked(vib, intensity);
+            applyVibrationIntensityScalingLocked(vib);
             startVibrationInnerLocked(vib);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1171,73 +1091,12 @@
                 || usage == VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
     }
 
-    private int getCurrentIntensityLocked(int usageHint) {
-        if (isRingtone(usageHint)) {
-            return mRingIntensity;
-        } else if (isNotification(usageHint)) {
-            return mNotificationIntensity;
-        } else if (isHapticFeedback(usageHint)) {
-            return mHapticFeedbackIntensity;
-        } else if (isAlarm(usageHint)) {
-            return Vibrator.VIBRATION_INTENSITY_HIGH;
-        } else {
-            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
-        }
-    }
-
-    private int getDefaultIntensity(int usageHint) {
-        if (isRingtone(usageHint)) {
-            return mVibrator.getDefaultRingVibrationIntensity();
-        } else if (isNotification(usageHint)) {
-            return mVibrator.getDefaultNotificationVibrationIntensity();
-        } else if (isHapticFeedback(usageHint)) {
-            return mVibrator.getDefaultHapticFeedbackIntensity();
-        } else if (isAlarm(usageHint)) {
-            return Vibrator.VIBRATION_INTENSITY_HIGH;
-        } else {
-            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
-        }
-    }
-
-    /**
-     * Scale the vibration effect by the intensity as appropriate based its intent.
-     */
-    private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
-        if (vib.effect instanceof VibrationEffect.Prebaked) {
-            // Prebaked effects are always just a direct translation from intensity to
-            // EffectStrength.
-            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
-            prebaked.setEffectStrength(intensityToEffectStrength(intensity));
-            return;
-        }
-
-        final int defaultIntensity = getDefaultIntensity(vib.attrs.getUsage());
-        final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
-        if (scale == null) {
-            // We should have scaling levels for all cases, so not being able to scale because of a
-            // missing level is unexpected.
-            Slog.e(TAG, "No configured scaling level!"
-                    + " (current=" + intensity + ", default= " + defaultIntensity + ")");
-            return;
-        }
-
-        vib.originalEffect = vib.effect;
-        vib.effect = vib.effect.resolve(mDefaultVibrationAmplitude).scale(scale.factor);
-        vib.scale = scale.factor;
-    }
-
-    private boolean shouldVibrateForRingtone() {
-        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
-        int ringerMode = audioManager.getRingerModeInternal();
-        // "Also vibrate for calls" Setting in Sound
-        if (Settings.System.getInt(
-                mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
-            return ringerMode != AudioManager.RINGER_MODE_SILENT;
-        } else if (Settings.Global.getInt(
-                    mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0) {
-            return ringerMode != AudioManager.RINGER_MODE_SILENT;
-        } else {
-            return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+    /** Scale the vibration effect by the intensity as appropriate based its intent. */
+    private void applyVibrationIntensityScalingLocked(Vibration vib) {
+        VibrationEffect scaled = mVibrationScaler.scale(vib.effect, vib.attrs.getUsage());
+        if (!scaled.equals(vib.effect)) {
+            vib.originalEffect = vib.effect;
+            vib.effect = scaled;
         }
     }
 
@@ -1262,18 +1121,19 @@
         return mode;
     }
 
-    private boolean shouldVibrate(Vibration vib, int intensity) {
+    private boolean shouldVibrate(Vibration vib) {
         if (!shouldVibrateForPowerModeLocked(vib)) {
             endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_POWER);
             return false;
         }
 
+        int intensity = mVibrationSettings.getCurrentIntensity(vib.attrs.getUsage());
         if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
             endVibrationLocked(vib, VibrationInfo.Status.IGNORED_FOR_SETTINGS);
             return false;
         }
 
-        if (vib.isRingtone() && !shouldVibrateForRingtone()) {
+        if (vib.isRingtone() && !mVibrationSettings.shouldVibrateForRingtone()) {
             if (DEBUG) {
                 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
             }
@@ -1335,7 +1195,6 @@
         synchronized (mLock) {
             boolean devicesUpdated = updateInputDeviceVibratorsLocked();
             boolean lowPowerModeUpdated = updateLowPowerModeLocked();
-            updateVibrationIntensityLocked();
 
             if (devicesUpdated || lowPowerModeUpdated) {
                 // If the state changes out from under us then just reset.
@@ -1348,13 +1207,7 @@
 
     private boolean updateInputDeviceVibratorsLocked() {
         boolean changed = false;
-        boolean vibrateInputDevices = false;
-        try {
-            vibrateInputDevices = Settings.System.getIntForUser(
-                    mContext.getContentResolver(),
-                    Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
-        } catch (SettingNotFoundException snfe) {
-        }
+        boolean vibrateInputDevices = mVibrationSettings.shouldVibrateInputDevices();
         if (vibrateInputDevices != mVibrateInputDevicesSetting) {
             changed = true;
             mVibrateInputDevicesSetting = vibrateInputDevices;
@@ -1397,26 +1250,13 @@
         return false;
     }
 
-    private void updateVibrationIntensityLocked() {
-        mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_INTENSITY,
-                mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
-        mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
-                mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
-        mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
-                Settings.System.RING_VIBRATION_INTENSITY,
-                mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
-    }
-
     private void updateAlwaysOnLocked(int id, Vibration vib) {
-        final int intensity = getCurrentIntensityLocked(vib.attrs.getUsage());
-        if (!shouldVibrate(vib, intensity)) {
+        if (!shouldVibrate(vib)) {
             mNativeWrapper.vibratorAlwaysOnDisable(id);
         } else {
-            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
-            final int strength = intensityToEffectStrength(intensity);
-            mNativeWrapper.vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
+            VibrationEffect.Prebaked scaled = mVibrationScaler.scale(vib.effect,
+                    vib.attrs.getUsage());
+            mNativeWrapper.vibratorAlwaysOnEnable(id, scaled.getId(), scaled.getEffectStrength());
         }
     }
 
@@ -1459,8 +1299,8 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
         try {
             synchronized (mInputDeviceVibrators) {
-                final VibrationEffect.OneShot oneShot =
-                        (VibrationEffect.OneShot) vib.effect.resolve(mDefaultVibrationAmplitude);
+                final VibrationEffect.OneShot oneShot = vib.effect.resolve(
+                        mDefaultVibrationAmplitude);
                 if (DEBUG) {
                     Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
                             + " with amplitude " + oneShot.getAmplitude() + ".");
@@ -1547,9 +1387,8 @@
                     vib.opPkg, vib.reason + " (fallback)");
             // Set current vibration before starting it, so callback will work.
             mCurrentVibration = fallbackVib;
-            final int intensity = getCurrentIntensityLocked(fallbackVib.attrs.getUsage());
             linkVibration(fallbackVib);
-            applyVibrationIntensityScalingLocked(fallbackVib, intensity);
+            applyVibrationIntensityScalingLocked(fallbackVib);
             startVibrationInnerLocked(fallbackVib);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -1594,25 +1433,6 @@
         return mFallbackEffects.get(effectId);
     }
 
-    /**
-     * Return the current desired effect strength.
-     *
-     * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
-     */
-    private static int intensityToEffectStrength(int intensity) {
-        switch (intensity) {
-            case Vibrator.VIBRATION_INTENSITY_LOW:
-                return EffectStrength.LIGHT;
-            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
-                return EffectStrength.MEDIUM;
-            case Vibrator.VIBRATION_INTENSITY_HIGH:
-                return EffectStrength.STRONG;
-            default:
-                Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
-                return EffectStrength.STRONG;
-        }
-    }
-
     private static boolean isNotification(int usageHint) {
         return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
     }
@@ -1690,14 +1510,7 @@
             pw.println("  mVibratorStateListeners Count="
                     + mVibratorStateListeners.getRegisteredCallbackCount());
             pw.println("  mLowPowerMode=" + mLowPowerMode);
-            pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
-            pw.println("  mHapticFeedbackDefaultIntensity="
-                    + mVibrator.getDefaultHapticFeedbackIntensity());
-            pw.println("  mNotificationIntensity=" + mNotificationIntensity);
-            pw.println("  mNotificationDefaultIntensity="
-                    + mVibrator.getDefaultNotificationVibrationIntensity());
-            pw.println("  mRingIntensity=" + mRingIntensity);
-            pw.println("  mRingDefaultIntensity=" + mVibrator.getDefaultRingVibrationIntensity());
+            pw.println("  mVibrationSettings=" + mVibrationSettings);
             pw.println("  mSupportedEffects=" + mSupportedEffects);
             pw.println("  mSupportedPrimitives=" + mSupportedPrimitives);
             pw.println();
@@ -1746,15 +1559,17 @@
                     mVibratorUnderExternalControl);
             proto.write(VibratorServiceDumpProto.LOW_POWER_MODE, mLowPowerMode);
             proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY,
-                    mHapticFeedbackIntensity);
+                    mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
             proto.write(VibratorServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultHapticFeedbackIntensity());
-            proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY, mNotificationIntensity);
+                    mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+            proto.write(VibratorServiceDumpProto.NOTIFICATION_INTENSITY,
+                    mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION));
             proto.write(VibratorServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultNotificationVibrationIntensity());
-            proto.write(VibratorServiceDumpProto.RING_INTENSITY, mRingIntensity);
+                    mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+            proto.write(VibratorServiceDumpProto.RING_INTENSITY,
+                    mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
             proto.write(VibratorServiceDumpProto.RING_DEFAULT_INTENSITY,
-                    mVibrator.getDefaultRingVibrationIntensity());
+                    mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
 
             for (VibrationInfo info : mPreviousRingVibrations) {
                 info.dumpProto(proto, VibratorServiceDumpProto.PREVIOUS_RING_VIBRATIONS);
@@ -2080,7 +1895,7 @@
         @Override
         public int onExternalVibrationStart(ExternalVibration vib) {
             if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
-                return SCALE_MUTE;
+                return IExternalVibratorService.SCALE_MUTE;
             }
             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
                     vib.getUid(), -1 /*owningUid*/, true /*exported*/)
@@ -2088,7 +1903,7 @@
                 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
                         + " tried to play externally controlled vibration"
                         + " without VIBRATE permission, ignoring.");
-                return SCALE_MUTE;
+                return IExternalVibratorService.SCALE_MUTE;
             }
 
             int mode = getAppOpMode(vib.getUid(), vib.getPackage(), vib.getVibrationAttributes());
@@ -2101,10 +1916,9 @@
                 } else {
                     endVibrationLocked(vibHolder, VibrationInfo.Status.IGNORED_APP_OPS);
                 }
-                return SCALE_MUTE;
+                return IExternalVibratorService.SCALE_MUTE;
             }
 
-            final int scaleLevel;
             synchronized (mLock) {
                 if (mCurrentExternalVibration != null
                         && mCurrentExternalVibration.externalVibration.equals(vib)) {
@@ -2131,23 +1945,12 @@
                 mCurrentExternalVibration = new ExternalVibrationHolder(vib);
                 mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
                 vib.linkToDeath(mCurrentExternalDeathRecipient);
+                mCurrentExternalVibration.scale = mVibrationScaler.getExternalVibrationScale(
+                        vib.getVibrationAttributes().getUsage());
                 if (DEBUG) {
                     Slog.e(TAG, "Playing external vibration: " + vib);
                 }
-                int usage = vib.getVibrationAttributes().getUsage();
-                int defaultIntensity = getDefaultIntensity(usage);
-                int currentIntensity = getCurrentIntensityLocked(usage);
-                scaleLevel = currentIntensity - defaultIntensity;
-            }
-            if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
-                mCurrentExternalVibration.scale = scaleLevel;
-                return scaleLevel;
-            } else {
-                // Presumably we want to play this but something about our scaling has gone
-                // wrong, so just play with no scaling.
-                Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
-                        + scaleLevel + " for vibration " + vib);
-                return SCALE_NONE;
+                return mCurrentExternalVibration.scale;
             }
         }
 
@@ -2232,21 +2035,12 @@
         }
 
         private boolean checkDoNotDisturb(CommonOptions opts) {
-            try {
-                final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.ZEN_MODE);
-                if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
-                    try (PrintWriter pw = getOutPrintWriter();) {
-                        pw.print("Ignoring because device is on DND mode ");
-                        pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
-                                zenMode));
-                        return true;
-                    }
+            if (mVibrationSettings.isInZenMode() && !opts.force) {
+                try (PrintWriter pw = getOutPrintWriter();) {
+                    pw.print("Ignoring because device is on DND mode ");
+                    return true;
                 }
-            } catch (SettingNotFoundException e) {
-                // ignore
             }
-
             return false;
         }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4a338b3..e1124ab 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
 import static android.os.Process.NFC_UID;
@@ -145,7 +146,7 @@
     private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
 
     public static final int FGS_FEATURE_DENIED = 0;
-    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 1;
+    public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
     public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
     public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
     public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
@@ -154,10 +155,12 @@
     public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
     public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
     public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
+    public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
+    public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;
 
     @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
             FGS_FEATURE_DENIED,
-            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+            FGS_FEATURE_ALLOWED_BY_UID_STATE,
             FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
             FGS_FEATURE_ALLOWED_BY_FLAG,
             FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
@@ -165,7 +168,9 @@
             FGS_FEATURE_ALLOWED_BY_TOKEN,
             FGS_FEATURE_ALLOWED_BY_PERMISSION,
             FGS_FEATURE_ALLOWED_BY_WHITELIST,
-            FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER
+            FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
+            FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+            FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FgsFeatureRetCode {}
@@ -576,18 +581,11 @@
                 if (r.mAllowStartForeground == FGS_FEATURE_DENIED
                         && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
                         || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
-                    if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
-                            && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
-                        // uid is on DeviceIdleController's allowlist.
-                        Slog.d(TAG, "startForegroundService() mAllowStartForeground false "
-                                + "but allowlist true: service " + r.shortInstanceName);
-                    } else {
-                        Slog.w(TAG, "startForegroundService() not allowed due to "
-                                + "mAllowStartForeground false: service "
-                                + r.shortInstanceName);
-                        showFgsBgRestrictedNotificationLocked(r);
-                        return null;
-                    }
+                    Slog.w(TAG, "startForegroundService() not allowed due to "
+                            + "mAllowStartForeground false: service "
+                            + r.shortInstanceName);
+                    showFgsBgRestrictedNotificationLocked(r);
+                    return null;
                 }
             }
         }
@@ -1488,20 +1486,12 @@
                         if (r.mAllowStartForeground == FGS_FEATURE_DENIED
                                 && (mAm.mConstants.mFlagFgsStartRestrictionEnabled
                                 || isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
-                            if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
-                                    && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
-                                // uid is on DeviceIdleController's allowlist.
-                                Slog.d(TAG, "Service.startForeground() "
-                                        + "mAllowStartForeground false but allowlist true: service "
-                                        + r.shortInstanceName);
-                            } else {
-                                Slog.w(TAG, "Service.startForeground() not allowed due to "
-                                                + "mAllowStartForeground false: service "
-                                                + r.shortInstanceName);
-                                showFgsBgRestrictedNotificationLocked(r);
-                                updateServiceForegroundLocked(r.app, true);
-                                ignoreForeground = true;
-                            }
+                            Slog.w(TAG, "Service.startForeground() not allowed due to "
+                                            + "mAllowStartForeground false: service "
+                                            + r.shortInstanceName);
+                            showFgsBgRestrictedNotificationLocked(r);
+                            updateServiceForegroundLocked(r.app, true);
+                            ignoreForeground = true;
                         }
                     }
                 }
@@ -4944,38 +4934,39 @@
             r.mAllowWhileInUsePermissionInFgs = true;
         }
 
-        if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
-            final @FgsFeatureRetCode int temp = shouldAllowFgsFeatureLocked(callingPackage,
-                    callingPid, callingUid, intent, r, allowBackgroundActivityStarts);
+        if (!r.mAllowWhileInUsePermissionInFgs
+                || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
+            final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
+                    callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
             if (!r.mAllowWhileInUsePermissionInFgs) {
-                r.mAllowWhileInUsePermissionInFgs = (temp != FGS_FEATURE_DENIED);
+                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
             }
             if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
-                r.mAllowStartForeground = temp;
+                r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
+                        callingPackage, callingPid, callingUid, intent, r,
+                        allowBackgroundActivityStarts);
             }
         }
     }
 
     /**
-     * Should allow FGS feature or not.
+     * Should allow while-in-use permissions in FGS or not.
+     * A typical BG started FGS is not allowed to have while-in-use permissions.
      * @param callingPackage caller app's package name.
      * @param callingUid caller app's uid.
-     * @param intent intent to start/bind service.
      * @param r the service to start.
      * @return {@link FgsFeatureRetCode}
      */
-    private @FgsFeatureRetCode int shouldAllowFgsFeatureLocked(String callingPackage,
-            int callingPid, int callingUid, Intent intent, ServiceRecord r,
+    private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+            int callingPid, int callingUid, ServiceRecord r,
             boolean allowBackgroundActivityStarts) {
         int ret = FGS_FEATURE_DENIED;
 
-        final StringBuilder sb = new StringBuilder(64);
         final int uidState = mAm.getUidState(callingUid);
         if (ret == FGS_FEATURE_DENIED) {
             // Is the calling UID at PROCESS_STATE_TOP or above?
             if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
-                sb.append("uidState=").append(uidState);
-                ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
             }
         }
 
@@ -5010,7 +5001,6 @@
             }
 
             if (isCallerSystem) {
-                sb.append("callingUid=").append(callingAppId);
                 ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
             }
         }
@@ -5049,6 +5039,53 @@
                 ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
             }
         }
+        return ret;
+    }
+
+    /**
+     * Should allow the FGS to start (AKA startForeground()) or not.
+     * The check in this method is in addition to check in
+     * {@link #shouldAllowFgsWhileInUsePermissionLocked}
+     * @param allowWhileInUse the return code from {@link #shouldAllowFgsWhileInUsePermissionLocked}
+     * @param callingPackage caller app's package name.
+     * @param callingUid caller app's uid.
+     * @param intent intent to start/bind service.
+     * @param r the service to start.
+     * @return {@link FgsFeatureRetCode}
+     */
+    private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
+            @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
+            int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
+        int ret = allowWhileInUse;
+
+        final StringBuilder sb = new StringBuilder(64);
+        final int uidState = mAm.getUidState(callingUid);
+        if (ret == FGS_FEATURE_DENIED) {
+            // Is the calling UID at PROCESS_STATE_TOP or above?
+            if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
+                sb.append("uidState=").append(uidState);
+                ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
+            for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+                final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+                if (pr.uid == callingUid
+                        && pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+                    ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+                    break;
+                }
+            }
+        }
+
+        if (ret == FGS_FEATURE_DENIED) {
+            if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
+                    && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
+                // uid is on DeviceIdleController's allowlist.
+                ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+            }
+        }
 
         final String debugInfo =
                 "[callingPackage: " + callingPackage
@@ -5071,8 +5108,8 @@
         switch (code) {
             case FGS_FEATURE_DENIED:
                 return "DENIED";
-            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
-                return "ALLOWED_BY_PROC_STATE";
+            case FGS_FEATURE_ALLOWED_BY_UID_STATE:
+                return "ALLOWED_BY_UID_STATE";
             case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
                 return "ALLOWED_BY_UID_VISIBLE";
             case FGS_FEATURE_ALLOWED_BY_FLAG:
@@ -5089,13 +5126,17 @@
                 return "ALLOWED_BY_WHITELIST";
             case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
                 return "ALLOWED_BY_DEVICE_OWNER";
+            case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+                return "ALLOWED_BY_PROC_STATE";
+            case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
+                return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
             default:
                 return "";
         }
     }
 
     private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
-        return code != FGS_FEATURE_ALLOWED_BY_PROC_STATE
+        return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
                 && code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index b54a917e..9c4a358 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -91,6 +91,9 @@
     static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
     static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
     static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
+    static final String KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL =
+            "process_crash_count_reset_interval";
+    static final String KEY_PROCESS_CRASH_COUNT_LIMIT = "process_crash_count_limit";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -126,6 +129,8 @@
     private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
     private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
     private static final int DEFAULT_MAX_PHANTOM_PROCESSES = 32;
+    private static final int DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL = 12 * 60 * 60 * 1000;
+    private static final int DEFAULT_PROCESS_CRASH_COUNT_LIMIT = 12;
 
 
     // Flag stored in the DeviceConfig API.
@@ -301,9 +306,27 @@
     /**
      * The minimum time we allow between crashes, for us to consider this
      * application to be bad and stop its services and reject broadcasts.
+     * A reasonable interval here would be anything between 1-3 minutes.
      */
     public static int MIN_CRASH_INTERVAL = DEFAULT_MIN_CRASH_INTERVAL;
 
+    /**
+     * We will allow for a maximum number of {@link PROCESS_CRASH_COUNT_LIMIT} crashes within this
+     * time period before we consider the application to be bad and stop services and reject
+     * broadcasts.
+     * A reasonable reset interval here would be anything between 10-20 hours along with a crash
+     * count limit of 10-20 crashes.
+     */
+    static long PROCESS_CRASH_COUNT_RESET_INTERVAL = DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL;
+
+    /**
+     * The maximum number of crashes allowed within {@link PROCESS_CRASH_COUNT_RESET_INTERVAL_MS}
+     * before we consider the application to be bad and stop services and reject broadcasts.
+     * A reasonable crash count limit here would be anything between 10-20 crashes along with a
+     * reset interval of 10-20 hours.
+     */
+    static int PROCESS_CRASH_COUNT_LIMIT = DEFAULT_PROCESS_CRASH_COUNT_LIMIT;
+
     // Indicates whether the activity starts logging is enabled.
     // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
     volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -694,6 +717,11 @@
                     DEFAULT_MIN_CRASH_INTERVAL);
             PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
                     DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
+            PROCESS_CRASH_COUNT_RESET_INTERVAL = mParser.getInt(
+                    KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL,
+                    DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL);
+            PROCESS_CRASH_COUNT_LIMIT = mParser.getInt(KEY_PROCESS_CRASH_COUNT_LIMIT,
+                    DEFAULT_PROCESS_CRASH_COUNT_LIMIT);
 
             if (POWER_CHECK_INTERVAL != currentPowerCheckInterval) {
                 mService.mHandler.removeMessages(
@@ -934,6 +962,10 @@
         pw.println(TOP_TO_FGS_GRACE_DURATION);
         pw.print("  "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
         pw.println(MIN_CRASH_INTERVAL);
+        pw.print("  "); pw.print(KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL); pw.print("=");
+        pw.println(PROCESS_CRASH_COUNT_RESET_INTERVAL);
+        pw.print("  "); pw.print(KEY_PROCESS_CRASH_COUNT_LIMIT); pw.print("=");
+        pw.println(PROCESS_CRASH_COUNT_LIMIT);
         pw.print("  "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES); pw.print("=");
         pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
         pw.print("  "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index cf900ab..0b4d27f 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -19,6 +19,8 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
 
+import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_LIMIT;
+import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_RESET_INTERVAL;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -44,6 +46,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -90,6 +93,12 @@
     private final ProcessMap<Long> mProcessCrashShowDialogTimes = new ProcessMap<>();
 
     /**
+     * A pairing between how many times various processes have crashed since a given time.
+     * Entry and exit conditions for this map are similar to mProcessCrashTimes.
+     */
+    private final ProcessMap<Pair<Long, Integer>> mProcessCrashCounts = new ProcessMap<>();
+
+    /**
      * Set of applications that we consider to be bad, and will reject
      * incoming broadcasts from (which the user has no control over).
      * Processes are added to this set when they have crashed twice within
@@ -118,6 +127,7 @@
         mProcessCrashTimes.clear();
         mProcessCrashTimesPersistent.clear();
         mProcessCrashShowDialogTimes.clear();
+        mProcessCrashCounts.clear();
         synchronized (mBadProcesses) {
             mBadProcesses.clear();
         }
@@ -196,9 +206,9 @@
     }
 
     boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
+        final long now = SystemClock.uptimeMillis();
         if (!mProcessCrashTimes.getMap().isEmpty()) {
             boolean printed = false;
-            final long now = SystemClock.uptimeMillis();
             final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
             final int processCount = pmap.size();
             for (int ip = 0; ip < processCount; ip++) {
@@ -227,6 +237,36 @@
             }
         }
 
+        if (!mProcessCrashCounts.getMap().isEmpty()) {
+            boolean printed = false;
+            final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pmap =
+                    mProcessCrashCounts.getMap();
+            final int processCount = pmap.size();
+            for (int ip = 0; ip < processCount; ip++) {
+                final String pname = pmap.keyAt(ip);
+                final SparseArray<Pair<Long, Integer>> uids = pmap.valueAt(ip);
+                final int uidCount = uids.size();
+                for (int i = 0; i < uidCount; i++) {
+                    final int puid = uids.keyAt(i);
+                    final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+                    if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+                        continue;
+                    }
+                    if (!printed) {
+                        if (needSep) pw.println();
+                        needSep = true;
+                        pw.println("  First time processes crashed and counts:");
+                        printed = true;
+                    }
+                    pw.print("    Process "); pw.print(pname);
+                    pw.print(" uid "); pw.print(puid);
+                    pw.print(": first crashed ");
+                    TimeUtils.formatDuration(now - uids.valueAt(i).first, pw);
+                    pw.print(" ago; crashes since then: "); pw.println(uids.valueAt(i).second);
+                }
+            }
+        }
+
         if (!mBadProcesses.getMap().isEmpty()) {
             boolean printed = false;
             final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
@@ -295,34 +335,50 @@
 
     void resetProcessCrashTimeLocked(final String processName, final int uid) {
         mProcessCrashTimes.remove(processName, uid);
+        mProcessCrashCounts.remove(processName, uid);
     }
 
     void resetProcessCrashTimeLocked(boolean resetEntireUser, int appId, int userId) {
-        final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
-        for (int ip = pmap.size() - 1; ip >= 0; ip--) {
-            SparseArray<Long> ba = pmap.valueAt(ip);
-            for (int i = ba.size() - 1; i >= 0; i--) {
-                boolean remove = false;
-                final int entUid = ba.keyAt(i);
-                if (!resetEntireUser) {
-                    if (userId == UserHandle.USER_ALL) {
-                        if (UserHandle.getAppId(entUid) == appId) {
-                            remove = true;
-                        }
-                    } else {
-                        if (entUid == UserHandle.getUid(userId, appId)) {
-                            remove = true;
-                        }
-                    }
-                } else if (UserHandle.getUserId(entUid) == userId) {
-                    remove = true;
-                }
-                if (remove) {
-                    ba.removeAt(i);
-                }
-            }
+        final ArrayMap<String, SparseArray<Long>> pTimeMap = mProcessCrashTimes.getMap();
+        for (int ip = pTimeMap.size() - 1; ip >= 0; ip--) {
+            SparseArray<Long> ba = pTimeMap.valueAt(ip);
+            resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
             if (ba.size() == 0) {
-                pmap.removeAt(ip);
+                pTimeMap.removeAt(ip);
+            }
+        }
+
+        final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pCountMap =
+                                                                    mProcessCrashCounts.getMap();
+        for (int ip = pCountMap.size() - 1; ip >= 0; ip--) {
+            SparseArray<Pair<Long, Integer>> ba = pCountMap.valueAt(ip);
+            resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
+            if (ba.size() == 0) {
+                pCountMap.removeAt(ip);
+            }
+        }
+    }
+
+    private void resetProcessCrashMapLocked(SparseArray<?> ba, boolean resetEntireUser,
+            int appId, int userId) {
+        for (int i = ba.size() - 1; i >= 0; i--) {
+            boolean remove = false;
+            final int entUid = ba.keyAt(i);
+            if (!resetEntireUser) {
+                if (userId == UserHandle.USER_ALL) {
+                    if (UserHandle.getAppId(entUid) == appId) {
+                        remove = true;
+                    }
+                } else {
+                    if (entUid == UserHandle.getUid(userId, appId)) {
+                        remove = true;
+                    }
+                }
+            } else if (UserHandle.getUserId(entUid) == userId) {
+                remove = true;
+            }
+            if (remove) {
+                ba.removeAt(i);
             }
         }
     }
@@ -567,12 +623,6 @@
             if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
                 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
             }
-            if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
-                // XXX Can't keep track of crash time for isolated processes,
-                // since they don't have a persistent identity.
-                mProcessCrashTimes.put(r.processName, r.uid,
-                        SystemClock.uptimeMillis());
-            }
         }
 
         if (appErrorIntent != null) {
@@ -742,11 +792,14 @@
             }
         }
 
-        if (crashTime != null && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
-            // The process crashed again very quickly. If it was a bound foreground service, let's
-            // try to restart again in a while, otherwise the process loses!
-            Slog.w(TAG, "Process " + app.processName
-                    + " has crashed too many times: killing!");
+        final boolean quickCrash = crashTime != null
+                && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
+        if (quickCrash || isProcOverCrashLimit(app, now)) {
+            // The process either crashed again very quickly or has been crashing periodically in
+            // the last few hours. If it was a bound foreground service, let's try to restart again
+            // in a while, otherwise the process loses!
+            Slog.w(TAG, "Process " + app.processName + " has crashed too many times, killing!"
+                    + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit"));
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                     app.userId, app.processName, app.uid);
             mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
@@ -765,6 +818,7 @@
                                 new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
                     }
                     mProcessCrashTimes.remove(app.processName, app.uid);
+                    mProcessCrashCounts.remove(app.processName, app.uid);
                 }
                 app.bad = true;
                 app.removed = true;
@@ -809,12 +863,30 @@
             // because they don't have a persistent identity.
             mProcessCrashTimes.put(app.processName, app.uid, now);
             mProcessCrashTimesPersistent.put(app.processName, app.uid, now);
+            updateProcessCrashCount(app.processName, app.uid, now);
         }
 
         if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
         return true;
     }
 
+    private void updateProcessCrashCount(String processName, int uid, long now) {
+        Pair<Long, Integer> count = mProcessCrashCounts.get(processName, uid);
+        if (count == null || (count.first + PROCESS_CRASH_COUNT_RESET_INTERVAL) < now) {
+            count = new Pair<>(now, 1);
+        } else {
+            count = new Pair<>(count.first, count.second + 1);
+        }
+        mProcessCrashCounts.put(processName, uid, count);
+    }
+
+    private boolean isProcOverCrashLimit(ProcessRecord app, long now) {
+        final Pair<Long, Integer> crashCount = mProcessCrashCounts.get(app.processName, app.uid);
+        return !app.isolated && crashCount != null
+                && now < (crashCount.first + PROCESS_CRASH_COUNT_RESET_INTERVAL)
+                && crashCount.second >= PROCESS_CRASH_COUNT_LIMIT;
+    }
+
     void handleShowAppErrorUi(Message msg) {
         AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
         boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 29431b1..6765132 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -585,10 +585,10 @@
                 synchronized (mStats) {
                     mStats.noteSyncStartLocked(name, uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
-                        name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+                name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
     }
 
     public void noteSyncFinish(final String name, final int uid) {
@@ -600,10 +600,10 @@
                 synchronized (mStats) {
                     mStats.noteSyncFinishLocked(name, uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
-                        name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+                name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
     }
 
     /** A scheduled job was started. */
@@ -849,10 +849,10 @@
                 synchronized (mStats) {
                     mStats.noteStartSensorLocked(uid, sensor, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
-                        null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+                null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
     }
 
     public void noteStopSensor(final int uid, final int sensor) {
@@ -864,10 +864,10 @@
                 synchronized (mStats) {
                     mStats.noteStopSensorLocked(uid, sensor, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
-                        null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+                null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteVibratorOn(final int uid, final long durationMillis) {
@@ -935,10 +935,10 @@
                 synchronized (mStats) {
                     mStats.noteScreenStateLocked(state, elapsedRealtime, uptime, currentTime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
                 if (DBG) Slog.d(TAG, "end noteScreenState");
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
     }
 
     public void noteScreenBrightness(final int brightness) {
@@ -950,9 +950,9 @@
                 synchronized (mStats) {
                     mStats.noteScreenBrightnessLocked(brightness, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
     }
 
     public void noteUserActivity(final int uid, final int event) {
@@ -1103,10 +1103,10 @@
                 synchronized (mStats) {
                     mStats.noteWifiOnLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
-                        FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+                FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
     }
 
     public void noteWifiOff() {
@@ -1118,10 +1118,10 @@
                 synchronized (mStats) {
                     mStats.noteWifiOffLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
-                        FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+                FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteStartAudio(final int uid) {
@@ -1133,10 +1133,10 @@
                 synchronized (mStats) {
                     mStats.noteAudioOnLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
     }
 
     public void noteStopAudio(final int uid) {
@@ -1148,10 +1148,10 @@
                 synchronized (mStats) {
                     mStats.noteAudioOffLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteStartVideo(final int uid) {
@@ -1163,10 +1163,10 @@
                 synchronized (mStats) {
                     mStats.noteVideoOnLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
-                        uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+                uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
     }
 
     public void noteStopVideo(final int uid) {
@@ -1178,10 +1178,10 @@
                 synchronized (mStats) {
                     mStats.noteVideoOffLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
-                        uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+                uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteResetAudio() {
@@ -1193,10 +1193,10 @@
                 synchronized (mStats) {
                     mStats.noteResetAudioLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
-                        FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
+                FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
     }
 
     public void noteResetVideo() {
@@ -1208,10 +1208,10 @@
                 synchronized (mStats) {
                     mStats.noteResetVideoLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
-                        null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
+                null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
     }
 
     public void noteFlashlightOn(final int uid) {
@@ -1223,10 +1223,10 @@
                 synchronized (mStats) {
                     mStats.noteFlashlightOnLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
     }
 
     public void noteFlashlightOff(final int uid) {
@@ -1238,10 +1238,10 @@
                 synchronized (mStats) {
                     mStats.noteFlashlightOffLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteStartCamera(final int uid) {
@@ -1254,11 +1254,11 @@
                 synchronized (mStats) {
                     mStats.noteCameraOnLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
             });
         }
         if (DBG) Slog.d(TAG, "end noteStartCamera");
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
     }
 
     public void noteStopCamera(final int uid) {
@@ -1270,10 +1270,10 @@
                 synchronized (mStats) {
                     mStats.noteCameraOffLocked(uid, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
-                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+                null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteResetCamera() {
@@ -1285,10 +1285,10 @@
                 synchronized (mStats) {
                     mStats.noteResetCameraLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1,
-                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1,
+                null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
     }
 
     public void noteResetFlashlight() {
@@ -1300,10 +1300,10 @@
                 synchronized (mStats) {
                     mStats.noteResetFlashlightLocked(elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
-                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
             });
         }
+        FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
+                null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
     }
 
     @Override
@@ -1341,11 +1341,11 @@
                 synchronized (mStats) {
                     mStats.noteWifiRunningLocked(localWs, elapsedRealtime, uptime);
                 }
-                // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                        ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
             });
         }
+        // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
     }
 
     public void noteWifiRunningChanged(final WorkSource oldWs, final WorkSource newWs) {
@@ -1360,12 +1360,12 @@
                     mStats.noteWifiRunningChangedLocked(
                             localOldWs, localNewWs, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                        newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                        oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteWifiStopped(final WorkSource ws) {
@@ -1378,10 +1378,10 @@
                 synchronized (mStats) {
                     mStats.noteWifiStoppedLocked(localWs, elapsedRealtime, uptime);
                 }
-                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                        ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteWifiState(final int wifiState, final String accessPoint) {
@@ -2421,11 +2421,6 @@
             final long elapsedRealtime = SystemClock.elapsedRealtime();
             final long uptime = SystemClock.uptimeMillis();
             mHandler.post(() -> {
-                FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
-                        uid, packageName, className,
-                        resumed
-                        ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND
-                        : FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
                 synchronized (mStats) {
                     if (resumed) {
                         mStats.noteActivityResumedLocked(uid, elapsedRealtime, uptime);
@@ -2435,6 +2430,11 @@
                 }
             });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+                uid, packageName, className,
+                resumed
+                        ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND
+                        : FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
     }
 
     void noteProcessDied(final int uid, final int pid) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index f1c5915..0877dd9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -798,7 +798,10 @@
                 mService.updateOomAdjPendingTargetsLocked(
                         OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
             }
+        } else if (filter.receiverList.app != null) {
+            mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
         }
+
         try {
             if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                     "Delivering to " + filter + " : " + r);
@@ -1132,6 +1135,10 @@
                         }
                     }
                     if (sendResult) {
+                        if (r.callerApp != null) {
+                            mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
+                                    r.callerApp);
+                        }
                         try {
                             if (DEBUG_BROADCAST) {
                                 Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index cd0d5b4..36d4a38 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -720,6 +720,16 @@
         }
     }
 
+    // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS
+    void unfreezeTemporarily(ProcessRecord app) {
+        synchronized (mAm) {
+            if (app.frozen) {
+                unfreezeAppLocked(app);
+                freezeAppAsync(app);
+            }
+        }
+    }
+
     @GuardedBy("mAm")
     void freezeAppAsync(ProcessRecord app) {
         mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 01d0a6d..771f273 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1329,6 +1329,8 @@
         app.setCached(false);
         app.shouldNotFreeze = false;
 
+        app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
         final int appUid = app.info.uid;
         final int logUid = mService.mCurOomAdjUid;
 
@@ -1349,6 +1351,7 @@
             app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
             app.curCapability = PROCESS_CAPABILITY_ALL;
             app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
+            app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT);
             // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
             // facilitate this, here we need to determine whether or not it
@@ -1403,6 +1406,7 @@
             app.adjType = "top-activity";
             foregroundActivities = true;
             procState = PROCESS_STATE_CUR_TOP;
+            app.bumpAllowStartFgsState(PROCESS_STATE_TOP);
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
             }
@@ -1500,6 +1504,7 @@
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 procState = PROCESS_STATE_FOREGROUND_SERVICE;
+                app.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
                 app.adjType = "fg-service";
                 app.setCached(false);
                 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -1887,7 +1892,9 @@
                                 // into the top state, since they are not on top.  Instead
                                 // give them the best bound state after that.
                                 if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
-                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;                                                                                                                       ;
+                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    app.bumpAllowStartFgsState(
+                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
                                 } else if (mService.mWakefulness
                                         == PowerManagerInternal.WAKEFULNESS_AWAKE
                                         && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
@@ -1901,6 +1908,7 @@
                                 // Go at most to BOUND_TOP, unless requested to elevate
                                 // to client's state.
                                 clientProcState = PROCESS_STATE_BOUND_TOP;
+                                app.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
                                 boolean enabled = false;
                                 try {
                                     enabled = mPlatformCompatCache.isChangeEnabled(
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 463ba6d..85c5bdc 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -353,6 +353,10 @@
 
     long mKillTime; // The timestamp in uptime when this process was killed.
 
+    // If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS.
+    // It must obtain the proc state from a persistent/top process or FGS, not transitive.
+    int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
     void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
             long startTime) {
         this.startUid = startUid;
@@ -466,6 +470,8 @@
                 pw.print(" setCapability=");
                 ActivityManager.printCapabilitiesFull(pw, setCapability);
                 pw.println();
+        pw.print(prefix); pw.print("allowStartFgsState=");
+                pw.println(mAllowStartFgsState);
         if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
                     pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
@@ -1252,7 +1258,6 @@
 
     void setHasForegroundActivities(boolean hasForegroundActivities) {
         mHasForegroundActivities = hasForegroundActivities;
-        mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
     }
 
     boolean hasForegroundActivities() {
@@ -1943,6 +1948,12 @@
         return mDialogController;
     }
 
+    void bumpAllowStartFgsState(int newProcState) {
+        if (newProcState < mAllowStartFgsState) {
+            mAllowStartFgsState = newProcState;
+        }
+    }
+
     /** A controller to generate error dialogs in {@link ProcessRecord} */
     class ErrorDialogController {
         /** dialogs being displayed due to crash */
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 2b2d9b55..d434783 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3026,15 +3026,18 @@
                 mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
 
         final String voiceRecognitionServicePackageName =
-                voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
-                        voiceRecognitionComponent).getPackageName() : "";
+                getComponentPackageNameFromString(voiceRecognitionComponent);
         final String voiceInteractionServicePackageName =
-                voiceInteractionComponent != null ? ComponentName.unflattenFromString(
-                        voiceInteractionComponent).getPackageName() : "";
+                getComponentPackageNameFromString(voiceInteractionComponent);
         return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
                 voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
     }
 
+    private String getComponentPackageNameFromString(String from) {
+        ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+        return componentName != null ? componentName.getPackageName() : "";
+    }
+
     @Override
     public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
             String proxiedAttributionTag, int proxyUid, String proxyPackageName,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java b/services/core/java/com/android/server/biometrics/sensors/LockoutCache.java
similarity index 86%
rename from services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java
rename to services/core/java/com/android/server/biometrics/sensors/LockoutCache.java
index 2fae1f3..0aba295 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutCache.java
@@ -14,21 +14,19 @@
  * limitations under the License.
  */
 
-package com.android.server.biometrics.sensors.fingerprint.aidl;
+package com.android.server.biometrics.sensors;
 
 import android.util.SparseIntArray;
 
-import com.android.server.biometrics.sensors.LockoutTracker;
-
 /**
  * For a single sensor, caches lockout states for all users.
  */
-class LockoutCache implements LockoutTracker {
+public class LockoutCache implements LockoutTracker {
 
     // Map of userId to LockoutMode
     private final SparseIntArray mUserLockoutStates;
 
-    LockoutCache() {
+    public LockoutCache() {
         mUserLockoutStates = new SparseIntArray();
     }
 
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 00a708d..65e57f1 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
@@ -27,13 +27,19 @@
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.IBiometricSensorReceiver;
 import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.Face;
 import android.hardware.face.FaceSensorPropertiesInternal;
 import android.hardware.face.IFaceService;
 import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Pair;
 import android.util.Slog;
@@ -42,11 +48,13 @@
 
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.biometrics.Utils;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.aidl.FaceProvider;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -508,6 +516,38 @@
         mLockoutResetDispatcher = new LockoutResetDispatcher(context);
         mLockPatternUtils = new LockPatternUtils(context);
         mServiceProviders = new ArrayList<>();
+
+        initializeAidlHals();
+    }
+
+    private void initializeAidlHals() {
+        final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
+        if (instances == null || instances.length == 0) {
+            return;
+        }
+
+        // If for some reason the HAL is not started before the system service, do not block
+        // the rest of system server. Put this on a background thread.
+        final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+                true /* allowIo */);
+        thread.start();
+        final Handler handler = new Handler(thread.getLooper());
+
+        handler.post(() -> {
+            for (String instance : instances) {
+                final String fqName = IFace.DESCRIPTOR + "/" + instance;
+                final IFace face = IFace.Stub.asInterface(
+                        ServiceManager.waitForDeclaredService(fqName));
+                try {
+                    final SensorProps[] props = face.getSensorProps();
+                    final FaceProvider provider = new FaceProvider(getContext(), props, instance,
+                            mLockoutResetDispatcher);
+                    mServiceProviders.add(provider);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Remote exception when initializing instance: " + fqName);
+                }
+            }
+        });
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
new file mode 100644
index 0000000..80f337f
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -0,0 +1,221 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.FaceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.UsageStats;
+
+import java.util.ArrayList;
+
+/**
+ * Face-specific authentication client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceAuthenticationClient extends AuthenticationClient<ISession> implements LockoutConsumer {
+    private static final String TAG = "FaceAuthenticationClient";
+
+    @NonNull private final UsageStats mUsageStats;
+    @NonNull private final LockoutCache mLockoutCache;
+    @Nullable private final NotificationManager mNotificationManager;
+    @Nullable private ICancellationSignal mCancellationSignal;
+
+    private final int[] mBiometricPromptIgnoreList;
+    private final int[] mBiometricPromptIgnoreListVendor;
+    private final int[] mKeyguardIgnoreList;
+    private final int[] mKeyguardIgnoreListVendor;
+
+    private int mLastAcquire;
+
+    FaceAuthenticationClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+            @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
+            boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
+            boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
+            @NonNull LockoutCache lockoutCache) {
+        super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
+                owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
+                BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
+                lockoutCache);
+        mUsageStats = usageStats;
+        mLockoutCache = lockoutCache;
+        mNotificationManager = context.getSystemService(NotificationManager.class);
+
+        final Resources resources = getContext().getResources();
+        mBiometricPromptIgnoreList = resources.getIntArray(
+                R.array.config_face_acquire_biometricprompt_ignorelist);
+        mBiometricPromptIgnoreListVendor = resources.getIntArray(
+                R.array.config_face_acquire_vendor_biometricprompt_ignorelist);
+        mKeyguardIgnoreList = resources.getIntArray(
+                R.array.config_face_acquire_keyguard_ignorelist);
+        mKeyguardIgnoreListVendor = resources.getIntArray(
+                R.array.config_face_acquire_vendor_keyguard_ignorelist);
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception when requesting auth", e);
+            onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+
+    @Override
+    protected void stopHalOperation() {
+        if (mCancellationSignal != null) {
+            try {
+                mCancellationSignal.cancel();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception when requesting cancel", e);
+                onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+                mCallback.onClientFinished(this, false /* success */);
+            }
+        }
+    }
+
+    private boolean wasUserDetected() {
+        // Do not provide haptic feedback if the user was not detected, and an error (usually
+        // ERROR_TIMEOUT) is received.
+        return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
+                && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY;
+    }
+
+    @Override
+    public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
+            boolean authenticated, ArrayList<Byte> token) {
+        super.onAuthenticated(identifier, authenticated, token);
+
+        mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
+                getStartTimeMs(),
+                System.currentTimeMillis() - getStartTimeMs() /* latency */,
+                authenticated,
+                0 /* error */,
+                0 /* vendorError */,
+                getTargetUserId()));
+
+        // For face, the authentication lifecycle ends either when
+        // 1) Authenticated == true
+        // 2) Error occurred
+        // 3) Authenticated == false
+        mCallback.onClientFinished(this, true /* success */);
+    }
+
+    @Override
+    public void onError(int error, int vendorCode) {
+        mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
+                getStartTimeMs(),
+                System.currentTimeMillis() - getStartTimeMs() /* latency */,
+                false /* authenticated */,
+                error,
+                vendorCode,
+                getTargetUserId()));
+
+        switch (error) {
+            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
+                if (!wasUserDetected() && !isBiometricPrompt()) {
+                    // No vibration if user was not detected on keyguard
+                    break;
+                }
+            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+                if (mAuthAttempted) {
+                    // Only vibrate if auth was attempted. If the user was already locked out prior
+                    // to starting authentication, do not vibrate.
+                    vibrateError();
+                }
+                break;
+            default:
+                break;
+        }
+
+        super.onError(error, vendorCode);
+    }
+
+    private int[] getAcquireIgnorelist() {
+        return isBiometricPrompt() ? mBiometricPromptIgnoreList : mKeyguardIgnoreList;
+    }
+
+    private int[] getAcquireVendorIgnorelist() {
+        return isBiometricPrompt() ? mBiometricPromptIgnoreListVendor : mKeyguardIgnoreListVendor;
+    }
+
+    private boolean shouldSend(int acquireInfo, int vendorCode) {
+        if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) {
+            return !Utils.listContains(getAcquireVendorIgnorelist(), vendorCode);
+        } else {
+            return !Utils.listContains(getAcquireIgnorelist(), acquireInfo);
+        }
+    }
+
+    @Override
+    public void onAcquired(int acquireInfo, int vendorCode) {
+        mLastAcquire = acquireInfo;
+
+        final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
+        onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
+    }
+
+    @Override public void onLockoutTimed(long durationMillis) {
+        mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
+        // Lockout metrics are logged as an error code.
+        final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
+        logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+        try {
+            getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    @Override public void onLockoutPermanent() {
+        mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
+        // Lockout metrics are logged as an error code.
+        final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
+        logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+        try {
+            getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
new file mode 100644
index 0000000..f950862
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -0,0 +1,120 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.os.IBinder;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Face-specific enroll client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceEnrollClient extends EnrollClient<ISession> {
+
+    private static final String TAG = "FaceEnrollClient";
+
+    @NonNull private final int[] mEnrollIgnoreList;
+    @NonNull private final int[] mEnrollIgnoreListVendor;
+    @Nullable private ICancellationSignal mCancellationSignal;
+    private final int mMaxTemplatesPerUser;
+
+    FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+            @NonNull byte[] hardwareAuthToken, @NonNull String opPackageName,
+            @NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
+            @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) {
+        super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
+                timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
+                false /* shouldVibrate */);
+        mEnrollIgnoreList = getContext().getResources()
+                .getIntArray(R.array.config_face_acquire_enroll_ignorelist);
+        mEnrollIgnoreListVendor = getContext().getResources()
+                .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
+        mMaxTemplatesPerUser = maxTemplatesPerUser;
+    }
+
+    @Override
+    protected boolean hasReachedEnrollmentLimit() {
+        return FaceUtils.getInstance(getSensorId()).getBiometricsForUser(getContext(),
+                getTargetUserId()).size() >= mMaxTemplatesPerUser;
+    }
+
+    @Override
+    public void onAcquired(int acquireInfo, int vendorCode) {
+        final boolean shouldSend;
+        if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) {
+            shouldSend = !Utils.listContains(mEnrollIgnoreListVendor, vendorCode);
+        } else {
+            shouldSend = !Utils.listContains(mEnrollIgnoreList, acquireInfo);
+        }
+        onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
+    }
+
+    @Override
+    protected void startHalOperation() {
+        final ArrayList<Byte> token = new ArrayList<>();
+        for (byte b : mHardwareAuthToken) {
+            token.add(b);
+        }
+
+        try {
+            // TODO(b/172593978): Pass features.
+            // TODO(b/172593521): Pass mPreviewSurface as android.hardware.common.NativeHandle.
+            mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
+                    HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken),
+                    null /* mPreviewSurface */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception when requesting enroll", e);
+            onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+
+    @Override
+    protected void stopHalOperation() {
+        if (mCancellationSignal != null) {
+            try {
+                mCancellationSignal.cancel();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception when requesting cancel", e);
+                onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+                mCallback.onClientFinished(this, false /* success */);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
new file mode 100644
index 0000000..d7e08e4
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
@@ -0,0 +1,61 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
+
+/**
+ * Face-specific generateChallenge client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceGenerateChallengeClient extends GenerateChallengeClient<ISession> {
+    private static final String TAG = "FaceGenerateChallengeClient";
+    private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+
+    FaceGenerateChallengeClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+            @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
+        super(context, lazyDaemon, token, listener, owner, sensorId);
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            getFreshDaemon().generateChallenge(mSequentialId, CHALLENGE_TIMEOUT_SEC);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to generateChallenge", e);
+        }
+    }
+
+    void onChallengeGenerated(int sensorId, int userId, long challenge) {
+        try {
+            getListener().onChallengeGenerated(sensorId, challenge);
+            mCallback.onClientFinished(this, true /* success */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to send challenge", e);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
new file mode 100644
index 0000000..3280e98
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.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.server.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.ISession;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitor;
+
+import java.util.Map;
+
+class FaceGetAuthenticatorIdClient extends ClientMonitor<ISession> {
+
+    private static final String TAG = "FaceGetAuthenticatorIdClient";
+
+    private final Map<Integer, Long> mAuthenticatorIds;
+
+    FaceGetAuthenticatorIdClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+            int userId, @NonNull String opPackageName, int sensorId,
+            Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName,
+                0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FACE,
+                BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+        mAuthenticatorIds = authenticatorIds;
+    }
+
+    @Override
+    public void unableToStart() {
+        // Nothing to do here
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            getFreshDaemon().getAuthenticatorId(mSequentialId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    void onAuthenticatorIdRetrieved(long authenticatorId) {
+        mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
+        mCallback.onClientFinished(this, true /* success */);
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
new file mode 100644
index 0000000..9680e4e
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
@@ -0,0 +1,67 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.InternalCleanupClient;
+import com.android.server.biometrics.sensors.InternalEnumerateClient;
+import com.android.server.biometrics.sensors.RemovalClient;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Face-specific internal cleanup client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceInternalCleanupClient extends InternalCleanupClient<Face, ISession> {
+
+    FaceInternalCleanupClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, int userId, @NonNull String owner,
+            int sensorId, @NonNull List<Face> enrolledList, @NonNull BiometricUtils<Face> utils,
+            @NonNull Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE,
+                enrolledList, utils, authenticatorIds);
+    }
+
+    @Override
+    protected InternalEnumerateClient<ISession> getEnumerateClient(Context context,
+            LazyDaemon<ISession> lazyDaemon, IBinder token, int userId, String owner,
+            List<Face> enrolledList, BiometricUtils<Face> utils, int sensorId) {
+        return new FaceInternalEnumerateClient(context, lazyDaemon, token, userId, owner,
+                enrolledList, utils, sensorId);
+    }
+
+    @Override
+    protected RemovalClient<Face, ISession> getRemovalClient(Context context,
+            LazyDaemon<ISession> lazyDaemon, IBinder token,
+            int biometricId, int userId, String owner, BiometricUtils<Face> utils, int sensorId,
+            Map<Integer, Long> authenticatorIds) {
+        // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
+        // is all done internally.
+        return new FaceRemovalClient(context, lazyDaemon, token,
+                null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
+                sensorId, authenticatorIds);
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
new file mode 100644
index 0000000..75888a5
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
@@ -0,0 +1,57 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.InternalEnumerateClient;
+
+import java.util.List;
+
+/**
+ * Face-specific internal enumerate client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceInternalEnumerateClient extends InternalEnumerateClient<ISession> {
+    private static final String TAG = "FaceInternalEnumerateClient";
+
+    FaceInternalEnumerateClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, int userId,
+            @NonNull String owner, @NonNull List<Face> enrolledList,
+            @NonNull BiometricUtils<Face> utils, int sensorId) {
+        super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId,
+                BiometricsProtoEnums.MODALITY_FACE);
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            getFreshDaemon().enumerateEnrollments(mSequentialId);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception when requesting enumerate", e);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
new file mode 100644
index 0000000..590579a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -0,0 +1,580 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.SensorProps;
+import android.hardware.face.Face;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.face.IFaceServiceReceiver;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.PerformanceTracker;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+import com.android.server.biometrics.sensors.face.ServiceProvider;
+import com.android.server.biometrics.sensors.face.UsageStats;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provider for a single instance of the {@link IFace} HAL.
+ */
+public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
+    private static final String TAG = "FaceProvider";
+    private static final int ENROLL_TIMEOUT_SEC = 75;
+
+    @NonNull private final Context mContext;
+    @NonNull private final String mHalInstanceName;
+    @NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
+    @NonNull private final ClientMonitor.LazyDaemon<IFace> mLazyDaemon;
+    @NonNull private final Handler mHandler;
+    @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
+    @NonNull private final UsageStats mUsageStats;
+    @NonNull private final IActivityTaskManager mActivityTaskManager;
+    @NonNull private final BiometricTaskStackListener mTaskStackListener;
+
+    @Nullable private IFace mDaemon;
+
+    private final class BiometricTaskStackListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            mHandler.post(() -> {
+                for (int i = 0; i < mSensors.size(); i++) {
+                    final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+                            .getCurrentClient();
+                    if (!(client instanceof AuthenticationClient)) {
+                        Slog.e(getTag(), "Task stack changed for client: " + client);
+                        continue;
+                    }
+                    if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+                        continue; // Keyguard is always allowed
+                    }
+
+                    try {
+                        final List<ActivityManager.RunningTaskInfo> runningTasks =
+                                mActivityTaskManager.getTasks(1);
+                        if (!runningTasks.isEmpty()) {
+                            final String topPackage =
+                                    runningTasks.get(0).topActivity.getPackageName();
+                            if (!topPackage.contentEquals(client.getOwnerString())
+                                    && !client.isAlreadyDone()) {
+                                Slog.e(getTag(), "Stopping background authentication, top: "
+                                        + topPackage + " currentClient: " + client);
+                                mSensors.get(i).getScheduler()
+                                        .cancelAuthentication(client.getToken());
+                            }
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(getTag(), "Unable to get running tasks", e);
+                    }
+                }
+            });
+        }
+    }
+
+    public FaceProvider(@NonNull Context context, @NonNull SensorProps[] props,
+            @NonNull String halInstanceName,
+            @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+        mContext = context;
+        mHalInstanceName = halInstanceName;
+        mSensors = new SparseArray<>();
+        mLazyDaemon = this::getHalInstance;
+        mHandler = new Handler(Looper.getMainLooper());
+        mUsageStats = new UsageStats(context);
+        mLockoutResetDispatcher = lockoutResetDispatcher;
+        mActivityTaskManager = ActivityTaskManager.getService();
+        mTaskStackListener = new BiometricTaskStackListener();
+
+        for (SensorProps prop : props) {
+            final int sensorId = prop.commonProps.sensorId;
+
+            final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+                    prop.commonProps.sensorId, prop.commonProps.sensorStrength,
+                    prop.commonProps.maxEnrollmentsPerUser, false /* supportsFaceDetection */,
+                    prop.halControlsPreview);
+            final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
+                    internalProp);
+
+            mSensors.put(sensorId, sensor);
+            Slog.d(getTag(), "Added: " + internalProp);
+        }
+    }
+
+    private String getTag() {
+        return "FaceProvider/" + mHalInstanceName;
+    }
+
+    @Nullable
+    private synchronized IFace getHalInstance() {
+        if (mDaemon != null) {
+            return mDaemon;
+        }
+
+        Slog.d(getTag(), "Daemon was null, reconnecting");
+
+        mDaemon = IFace.Stub.asInterface(
+                ServiceManager.waitForDeclaredService(IFace.DESCRIPTOR + "/" + mHalInstanceName));
+        if (mDaemon == null) {
+            Slog.e(getTag(), "Unable to get daemon");
+            return null;
+        }
+
+        try {
+            mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
+        } catch (RemoteException e) {
+            Slog.e(getTag(), "Unable to linkToDeath", e);
+        }
+
+        for (int i = 0; i < mSensors.size(); i++) {
+            final int sensorId = mSensors.keyAt(i);
+            scheduleLoadAuthenticatorIds(sensorId);
+            scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser());
+        }
+
+        return mDaemon;
+    }
+
+    private void scheduleForSensor(int sensorId, @NonNull ClientMonitor<?> client) {
+        if (!mSensors.contains(sensorId)) {
+            throw new IllegalStateException("Unable to schedule client: " + client
+                    + " for sensor: " + sensorId);
+        }
+        mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+    }
+
+    private void scheduleForSensor(int sensorId, @NonNull ClientMonitor<?> client,
+            ClientMonitor.Callback callback) {
+        if (!mSensors.contains(sensorId)) {
+            throw new IllegalStateException("Unable to schedule client: " + client
+                    + " for sensor: " + sensorId);
+        }
+        mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
+    }
+
+    private void createNewSessionWithoutHandler(@NonNull IFace daemon, int sensorId,
+            int userId) throws RemoteException {
+        // Note that per IFingerprint createSession contract, this method will block until all
+        // existing operations are canceled/finished. However, also note that this is fine, since
+        // this method "withoutHandler" means it should only ever be invoked from the worker thread,
+        // so callers will never be blocked.
+        mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);
+    }
+
+
+    private void scheduleLoadAuthenticatorIds(int sensorId) {
+        for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
+            scheduleLoadAuthenticatorIdsForUser(sensorId, user.id);
+        }
+    }
+
+    private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during loadAuthenticatorIds, sensorId: " + sensorId);
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
+                        mContext, mSensors.get(sensorId).getLazySession(), userId,
+                        mContext.getOpPackageName(), sensorId,
+                        mSensors.get(sensorId).getAuthenticatorIds());
+
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling loadAuthenticatorId"
+                        + ", sensorId: " + sensorId
+                        + ", userId: " + userId, e);
+            }
+        });
+    }
+
+    @Override
+    public boolean containsSensor(int sensorId) {
+        return mSensors.contains(sensorId);
+    }
+
+    @NonNull
+    @Override
+    public List<FaceSensorPropertiesInternal> getSensorProperties() {
+        final List<FaceSensorPropertiesInternal> props = new ArrayList<>();
+        for (int i = 0; i < mSensors.size(); ++i) {
+            props.add(mSensors.valueAt(i).getSensorProperties());
+        }
+        return props;
+    }
+
+    @NonNull
+    @Override
+    public List<Face> getEnrolledFaces(int sensorId, int userId) {
+        return FaceUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId);
+    }
+
+    @Override
+    public int getLockoutModeForUser(int sensorId, int userId) {
+        return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
+    }
+
+    @Override
+    public long getAuthenticatorId(int sensorId, int userId) {
+        return mSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
+    }
+
+    @Override
+    public boolean isHardwareDetected(int sensorId) {
+        return getHalInstance() != null;
+    }
+
+    @Override
+    public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
+            @NonNull IFaceServiceReceiver receiver, String opPackageName) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during generateChallenge, sensorId: " + sensorId);
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
+                        mSensors.get(sensorId).getLazySession(), token,
+                        new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
+
+                scheduleForSensor(sensorId, client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling generateChallenge", e);
+            }
+        });
+    }
+
+    @Override
+    public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
+            @NonNull String opPackageName, long challenge) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during revokeChallenge, sensorId: " + sensorId);
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
+                        mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
+                        challenge);
+
+                scheduleForSensor(sensorId, client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling revokeChallenge", e);
+            }
+        });
+    }
+
+    @Override
+    public void scheduleEnroll(int sensorId, @NonNull IBinder token,
+            @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
+            @NonNull String opPackageName, @NonNull int[] disabledFeatures,
+            @Nullable NativeHandle previewSurface) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
+                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+                // this operation. We should not send the callback yet, since the scheduler may
+                // be processing something else.
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final int maxTemplatesPerUser = mSensors.get(
+                        sensorId).getSensorProperties().maxEnrollmentsPerUser;
+                final FaceEnrollClient client = new FaceEnrollClient(mContext,
+                        mSensors.get(sensorId).getLazySession(), token,
+                        new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
+                        opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
+                        ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser);
+                scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
+                    @Override
+                    public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
+                            boolean success) {
+                        if (success) {
+                            scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
+                        }
+                    }
+                });
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling enroll", e);
+            }
+        });
+    }
+
+    @Override
+    public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
+        mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelEnrollment(token));
+    }
+
+    @Override
+    public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+            int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+            @NonNull String opPackageName, boolean restricted, int statsClient,
+            boolean isKeyguard) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
+                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+                // this operation. We should not send the callback yet, since the scheduler may
+                // be processing something else.
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
+                final FaceAuthenticationClient client = new FaceAuthenticationClient(
+                        mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
+                        operationId, restricted, opPackageName, cookie,
+                        false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
+                        mUsageStats, mSensors.get(sensorId).getLockoutCache());
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
+            }
+        });
+    }
+
+    @Override
+    public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+        mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelAuthentication(token));
+    }
+
+    @Override
+    public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
+            @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
+                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+                // this operation. We should not send the callback yet, since the scheduler may
+                // be processing something else.
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final FaceRemovalClient client = new FaceRemovalClient(mContext,
+                        mSensors.get(sensorId).getLazySession(), token,
+                        new ClientMonitorCallbackConverter(receiver), faceId, userId,
+                        opPackageName, FaceUtils.getInstance(sensorId), sensorId,
+                        mSensors.get(sensorId).getAuthenticatorIds());
+
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling remove", e);
+            }
+        });
+    }
+
+    @Override
+    public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final FaceResetLockoutClient client = new FaceResetLockoutClient(
+                        mContext, mSensors.get(sensorId).getLazySession(), userId,
+                        mContext.getOpPackageName(), sensorId, hardwareAuthToken,
+                        mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
+
+                scheduleForSensor(sensorId, client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
+            }
+        });
+    }
+
+    @Override
+    public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
+            boolean enabled, @NonNull byte[] hardwareAuthToken,
+            @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+        // TODO(b/171335732): implement this.
+    }
+
+    @Override
+    public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
+            @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName) {
+        // TODO(b/171335732): implement this.
+    }
+
+    @Override
+    public void startPreparedClient(int sensorId, int cookie) {
+        mHandler.post(() -> {
+            mSensors.get(sensorId).getScheduler().startPreparedClient(cookie);
+        });
+    }
+
+    @Override
+    public void scheduleInternalCleanup(int sensorId, int userId) {
+        mHandler.post(() -> {
+            final IFace daemon = getHalInstance();
+            if (daemon == null) {
+                Slog.e(getTag(), "Null daemon during internal cleanup, sensorId: " + sensorId);
+                return;
+            }
+
+            try {
+                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+                    createNewSessionWithoutHandler(daemon, sensorId, userId);
+                }
+
+                final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
+                final FaceInternalCleanupClient client =
+                        new FaceInternalCleanupClient(mContext,
+                                mSensors.get(sensorId).getLazySession(), userId,
+                                mContext.getOpPackageName(), sensorId, enrolledList,
+                                FaceUtils.getInstance(sensorId),
+                                mSensors.get(sensorId).getAuthenticatorIds());
+
+                mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+            } catch (RemoteException e) {
+                Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
+            }
+        });
+    }
+
+    @Override
+    public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+
+    }
+
+    @Override
+    public void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd) {
+
+    }
+
+    @Override
+    public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
+        PerformanceTracker performanceTracker =
+                PerformanceTracker.getInstanceForSensorId(sensorId);
+
+        JSONObject dump = new JSONObject();
+        try {
+            dump.put("service", "Face Manager");
+
+            JSONArray sets = new JSONArray();
+            for (UserInfo user : UserManager.get(mContext).getUsers()) {
+                final int userId = user.getUserHandle().getIdentifier();
+                final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+                JSONObject set = new JSONObject();
+                set.put("id", userId);
+                set.put("count", c);
+                set.put("accept", performanceTracker.getAcceptForUser(userId));
+                set.put("reject", performanceTracker.getRejectForUser(userId));
+                set.put("acquire", performanceTracker.getAcquireForUser(userId));
+                set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
+                set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
+                // cryptoStats measures statistics about secure face transactions
+                // (e.g. to unlock password storage, make secure purchases, etc.)
+                set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
+                set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
+                set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
+                sets.put(set);
+            }
+
+            dump.put("prints", sets);
+        } catch (JSONException e) {
+            Slog.e(TAG, "dump formatting failure", e);
+        }
+        pw.println(dump);
+        pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+
+        mSensors.get(sensorId).getScheduler().dump(pw);
+        mUsageStats.print(pw);
+    }
+
+    @Override
+    public void binderDied() {
+        Slog.e(getTag(), "HAL died");
+        mHandler.post(() -> {
+            mDaemon = null;
+            for (int i = 0; i < mSensors.size(); i++) {
+                final int sensorId = mSensors.keyAt(i);
+                PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
+            }
+        });
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
new file mode 100644
index 0000000..1cb5031
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
@@ -0,0 +1,59 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.RemovalClient;
+
+import java.util.Map;
+
+/**
+ * Face-specific removal client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceRemovalClient extends RemovalClient<Face, ISession> {
+    private static final String TAG = "FaceRemovalClient";
+
+    FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+            int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils<Face> utils,
+            int sensorId, @NonNull Map<Integer, Long> authenticatorIds) {
+        super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+                authenticatorIds, BiometricsProtoEnums.MODALITY_FACE);
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            final int[] ids = new int[]{mBiometricId};
+            getFreshDaemon().removeEnrollments(mSequentialId, ids);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception when requesting remove", e);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
new file mode 100644
index 0000000..5d100ec
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -0,0 +1,79 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+/**
+ * Face-specific resetLockout client for the {@link IFace} AIDL HAL interface.
+ * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
+ * cleared.
+ */
+public class FaceResetLockoutClient extends ClientMonitor<ISession> {
+
+    private static final String TAG = "FaceResetLockoutClient";
+
+    private final HardwareAuthToken mHardwareAuthToken;
+    private final LockoutCache mLockoutCache;
+    private final LockoutResetDispatcher mLockoutResetDispatcher;
+
+    FaceResetLockoutClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, int userId, String owner, int sensorId,
+            @NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
+            @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+        super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+                0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+                BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+        mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
+        mLockoutCache = lockoutTracker;
+        mLockoutResetDispatcher = lockoutResetDispatcher;
+    }
+
+    @Override
+    public void unableToStart() {
+        // Nothing to do here
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to reset lockout", e);
+            mCallback.onClientFinished(this, false /* success */);
+        }
+    }
+
+    void onLockoutCleared() {
+        mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE);
+        mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
+        mCallback.onClientFinished(this, true /* success */);
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java
new file mode 100644
index 0000000..2863f9f
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java
@@ -0,0 +1,58 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
+
+/**
+ * Face-specific revokeChallenge client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceRevokeChallengeClient extends RevokeChallengeClient<ISession> {
+
+    private static final String TAG = "FaceRevokeChallengeClient";
+
+    private final long mChallenge;
+
+    FaceRevokeChallengeClient(@NonNull Context context,
+            @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+            @NonNull String owner, int sensorId, long challenge) {
+        super(context, lazyDaemon, token, owner, sensorId);
+        mChallenge = challenge;
+    }
+
+    @Override
+    protected void startHalOperation() {
+        try {
+            getFreshDaemon().revokeChallenge(mSequentialId, mChallenge);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to revokeChallenge", e);
+        }
+    }
+
+    void onChallengeRevoked(int sensorId, int userId, long challenge) {
+        final boolean success = challenge == mChallenge;
+        mCallback.onClientFinished(this, success);
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
new file mode 100644
index 0000000..ca1f17b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -0,0 +1,456 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.Error;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.biometrics.face.ISessionCallback;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.RemovalConsumer;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Maintains the state of a single sensor within an instance of the {@link IFace} HAL.
+ */
+public class Sensor implements IBinder.DeathRecipient {
+
+    @NonNull private final String mTag;
+    @NonNull private final FaceProvider mProvider;
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    @NonNull private final FaceSensorPropertiesInternal mSensorProperties;
+    @NonNull private final BiometricScheduler mScheduler;
+    @NonNull private final LockoutCache mLockoutCache;
+    @NonNull private final Map<Integer, Long> mAuthenticatorIds;
+    @NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
+    @Nullable private Session mCurrentSession;
+
+    @Override
+    public void binderDied() {
+        Slog.e(mTag, "Binder died");
+        mHandler.post(() -> {
+            final ClientMonitor<?> client = mScheduler.getCurrentClient();
+            if (client instanceof Interruptable) {
+                Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+                final Interruptable interruptable = (Interruptable) client;
+                interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
+                        0 /* vendorCode */);
+
+                mScheduler.recordCrashState();
+
+                FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+                        BiometricsProtoEnums.MODALITY_FACE,
+                        BiometricsProtoEnums.ISSUE_HAL_DEATH);
+                mCurrentSession = null;
+            }
+        });
+    }
+
+    static class Session {
+        @NonNull final HalSessionCallback mHalSessionCallback;
+        @NonNull private final String mTag;
+        @NonNull private final ISession mSession;
+        private final int mUserId;
+
+        Session(@NonNull String tag, @NonNull ISession session, int userId,
+                @NonNull HalSessionCallback halSessionCallback) {
+            mTag = tag;
+            mSession = session;
+            mUserId = userId;
+            mHalSessionCallback = halSessionCallback;
+            Slog.d(mTag, "New session created for user: " + userId);
+        }
+    }
+
+    Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+            @NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties) {
+        mTag = tag;
+        mProvider = provider;
+        mContext = context;
+        mHandler = handler;
+        mSensorProperties = sensorProperties;
+        mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
+        mLockoutCache = new LockoutCache();
+        mAuthenticatorIds = new HashMap<>();
+        mLazySession = () -> (mCurrentSession != null) ? mCurrentSession.mSession : null;
+    }
+
+    @NonNull ClientMonitor.LazyDaemon<ISession> getLazySession() {
+        return mLazySession;
+    }
+
+    @NonNull FaceSensorPropertiesInternal getSensorProperties() {
+        return mSensorProperties;
+    }
+
+    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+    boolean hasSessionForUser(int userId) {
+        return mCurrentSession != null && mCurrentSession.mUserId == userId;
+    }
+
+    @Nullable Session getSessionForUser(int userId) {
+        if (mCurrentSession != null && mCurrentSession.mUserId == userId) {
+            return mCurrentSession;
+        } else {
+            return null;
+        }
+    }
+
+    void createNewSession(@NonNull IFace daemon, int sensorId, int userId)
+            throws RemoteException {
+
+        final HalSessionCallback.Callback callback = () -> {
+            Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
+            mCurrentSession = null;
+        };
+        final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler,
+                mTag, mScheduler, sensorId, userId, callback);
+
+        final ISession newSession = daemon.createSession(sensorId, userId, resultController);
+        newSession.asBinder().linkToDeath(this, 0 /* flags */);
+        mCurrentSession = new Session(mTag, newSession, userId, resultController);
+    }
+
+    @NonNull BiometricScheduler getScheduler() {
+        return mScheduler;
+    }
+
+    @NonNull LockoutCache getLockoutCache() {
+        return mLockoutCache;
+    }
+
+    @NonNull Map<Integer, Long> getAuthenticatorIds() {
+        return mAuthenticatorIds;
+    }
+
+    static class HalSessionCallback extends ISessionCallback.Stub {
+        /**
+         * Interface to sends results to the HalSessionCallback's owner.
+         */
+        public interface Callback {
+            /**
+             * Invoked when the HAL sends ERROR_HW_UNAVAILABLE.
+             */
+            void onHardwareUnavailable();
+        }
+
+        @NonNull
+        private final Context mContext;
+        @NonNull
+        private final Handler mHandler;
+        @NonNull
+        private final String mTag;
+        @NonNull
+        private final BiometricScheduler mScheduler;
+        private final int mSensorId;
+        private final int mUserId;
+        @NonNull
+        private final Callback mCallback;
+
+        HalSessionCallback(@NonNull Context context, @NonNull Handler handler, @NonNull String tag,
+                @NonNull BiometricScheduler scheduler, int sensorId, int userId,
+                @NonNull Callback callback) {
+            mContext = context;
+            mHandler = handler;
+            mTag = tag;
+            mScheduler = scheduler;
+            mSensorId = sensorId;
+            mUserId = userId;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onStateChanged(int cookie, byte state) {
+            // TODO(b/162973174)
+        }
+
+        @Override
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceGenerateChallengeClient)) {
+                    Slog.e(mTag, "onChallengeGenerated for wrong client: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final FaceGenerateChallengeClient generateChallengeClient =
+                        (FaceGenerateChallengeClient) client;
+                generateChallengeClient.onChallengeGenerated(mSensorId, mUserId, challenge);
+            });
+        }
+
+        @Override
+        public void onChallengeRevoked(int sensorId, int userId, long challenge) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceRevokeChallengeClient)) {
+                    Slog.e(mTag, "onChallengeRevoked for wrong client: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final FaceRevokeChallengeClient revokeChallengeClient =
+                        (FaceRevokeChallengeClient) client;
+                revokeChallengeClient.onChallengeRevoked(mSensorId, mUserId, challenge);
+            });
+        }
+
+        @Override
+        public void onAcquired(byte info, int vendorCode) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof AcquisitionClient)) {
+                    Slog.e(mTag, "onAcquired for non-acquisition client: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
+                acquisitionClient.onAcquired(info, vendorCode);
+            });
+        }
+
+        @Override
+        public void onError(byte error, int vendorCode) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                Slog.d(mTag, "onError"
+                        + ", client: " + Utils.getClientName(client)
+                        + ", error: " + error
+                        + ", vendorCode: " + vendorCode);
+                if (!(client instanceof Interruptable)) {
+                    Slog.e(mTag, "onError for non-error consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final Interruptable interruptable = (Interruptable) client;
+                interruptable.onError(error, vendorCode);
+
+                if (error == Error.HW_UNAVAILABLE) {
+                    mCallback.onHardwareUnavailable();
+                }
+            });
+        }
+
+        @Override
+        public void onEnrollmentProgress(int enrollmentId, int remaining) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceEnrollClient)) {
+                    Slog.e(mTag, "onEnrollmentProgress for non-enroll client: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final int currentUserId = client.getTargetUserId();
+                final CharSequence name = FaceUtils.getInstance(mSensorId)
+                        .getUniqueName(mContext, currentUserId);
+                final Face face = new Face(name, enrollmentId, mSensorId);
+
+                final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
+                enrollClient.onEnrollResult(face, remaining);
+            });
+        }
+
+        @Override
+        public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof AuthenticationConsumer)) {
+                    Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final AuthenticationConsumer authenticationConsumer =
+                        (AuthenticationConsumer) client;
+                final Face face = new Face("" /* name */, enrollmentId, mSensorId);
+                final byte[] byteArray = HardwareAuthTokenUtils.toByteArray(hat);
+                final ArrayList<Byte> byteList = new ArrayList<>();
+                for (byte b : byteArray) {
+                    byteList.add(b);
+                }
+                authenticationConsumer.onAuthenticated(face, true /* authenticated */, byteList);
+            });
+        }
+
+        @Override
+        public void onAuthenticationFailed() {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof AuthenticationConsumer)) {
+                    Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final AuthenticationConsumer authenticationConsumer =
+                        (AuthenticationConsumer) client;
+                final Face face = new Face("" /* name */, 0 /* faceId */, mSensorId);
+                authenticationConsumer.onAuthenticated(face, false /* authenticated */,
+                        null /* hat */);
+            });
+        }
+
+        @Override
+        public void onLockoutTimed(long durationMillis) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof LockoutConsumer)) {
+                    Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+                lockoutConsumer.onLockoutTimed(durationMillis);
+            });
+        }
+
+        @Override
+        public void onLockoutPermanent() {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof LockoutConsumer)) {
+                    Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+                lockoutConsumer.onLockoutPermanent();
+            });
+        }
+
+        @Override
+        public void onLockoutCleared() {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceResetLockoutClient)) {
+                    Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final FaceResetLockoutClient resetLockoutClient = (FaceResetLockoutClient) client;
+                resetLockoutClient.onLockoutCleared();
+            });
+        }
+
+        @Override
+        public void onInteractionDetected() {
+            // no-op
+        }
+
+        @Override
+        public void onEnrollmentsEnumerated(int[] enrollmentIds) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof EnumerateConsumer)) {
+                    Slog.e(mTag, "onEnrollmentsEnumerated for non-enumerate consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final EnumerateConsumer enumerateConsumer =
+                        (EnumerateConsumer) client;
+                if (enrollmentIds.length > 0) {
+                    for (int i = 0; i < enrollmentIds.length; ++i) {
+                        final Face face = new Face("" /* name */, enrollmentIds[i], mSensorId);
+                        enumerateConsumer.onEnumerationResult(face, enrollmentIds.length - i - 1);
+                    }
+                } else {
+                    enumerateConsumer.onEnumerationResult(null /* identifier */, 0 /* remaining */);
+                }
+            });
+        }
+
+        @Override
+        public void onEnrollmentsRemoved(int[] enrollmentIds) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof RemovalConsumer)) {
+                    Slog.e(mTag, "onRemoved for non-removal consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final RemovalConsumer removalConsumer = (RemovalConsumer) client;
+                if (enrollmentIds.length > 0) {
+                    for (int i = 0; i < enrollmentIds.length; i++) {
+                        final Face face = new Face("" /* name */, enrollmentIds[i], mSensorId);
+                        removalConsumer.onRemoved(face, enrollmentIds.length - i - 1);
+                    }
+                } else {
+                    removalConsumer.onRemoved(null /* identifier */, 0 /* remaining */);
+                }
+            });
+        }
+
+        @Override
+        public void onAuthenticatorIdRetrieved(long authenticatorId) {
+            mHandler.post(() -> {
+                final ClientMonitor<?> client = mScheduler.getCurrentClient();
+                if (!(client instanceof FaceGetAuthenticatorIdClient)) {
+                    Slog.e(mTag, "onAuthenticatorIdRetrieved for wrong consumer: "
+                            + Utils.getClientName(client));
+                    return;
+                }
+
+                final FaceGetAuthenticatorIdClient getAuthenticatorIdClient =
+                        (FaceGetAuthenticatorIdClient) client;
+                getAuthenticatorIdClient.onAuthenticatorIdRetrieved(authenticatorId);
+            });
+        }
+
+        @Override
+        public void onAuthenticatorIdInvalidated() {
+            // TODO(b/159667191)
+        }
+
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 8acf4f5..ce0c439 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -32,6 +32,7 @@
 
 import com.android.server.biometrics.sensors.AuthenticationClient;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutConsumer;
 import com.android.server.biometrics.sensors.LockoutTracker;
 import com.android.server.biometrics.sensors.fingerprint.Udfps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 1718126..1f1d19d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -27,6 +27,7 @@
 
 import com.android.server.biometrics.HardwareAuthTokenUtils;
 import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 51c30b6..2e78912 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -49,6 +49,7 @@
 import com.android.server.biometrics.sensors.ClientMonitor;
 import com.android.server.biometrics.sensors.EnumerateConsumer;
 import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutConsumer;
 import com.android.server.biometrics.sensors.RemovalConsumer;
 import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 3385393..0563fcd 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -43,7 +43,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
 
 public class NetworkNotificationManager {
 
@@ -74,7 +73,12 @@
 
     private static final String TAG = NetworkNotificationManager.class.getSimpleName();
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+
+    // Notification channels used by ConnectivityService mainline module, it should be aligned with
+    // SystemNotificationChannels.
+    public static final String NOTIFICATION_NETWORK_STATUS = "NETWORK_STATUS";
+    public static final String NOTIFICATION_NETWORK_ALERTS = "NETWORK_ALERTS";
+    public static final String NOTIFICATION_VPN = "VPN";
 
     // The context is for the current user (system server)
     private final Context mContext;
@@ -259,8 +263,7 @@
         // the tag.
         final boolean hasPreviousNotification = previousNotifyType != null;
         final String channelId = (highPriority && !hasPreviousNotification)
-                ? SystemNotificationChannels.NETWORK_ALERTS
-                : SystemNotificationChannels.NETWORK_STATUS;
+                ? NOTIFICATION_NETWORK_ALERTS : NOTIFICATION_NETWORK_STATUS;
         Notification.Builder builder = new Notification.Builder(mContext, channelId)
                 .setWhen(System.currentTimeMillis())
                 .setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 6ac3e4a..ff017f89 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -27,6 +27,7 @@
 
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_VPN;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -111,7 +112,6 @@
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
 import com.android.internal.net.VpnProfile;
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.ConnectivityService;
 import com.android.server.DeviceIdleInternal;
@@ -1945,7 +1945,7 @@
             final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
                     intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
             final Notification.Builder builder =
-                    new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+                    new Notification.Builder(mContext, NOTIFICATION_VPN)
                             .setSmallIcon(R.drawable.vpn_connected)
                             .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
                             .setContentText(mContext.getString(R.string.vpn_lockdown_config))
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 838dc84..1fc15122 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -120,8 +120,13 @@
     }
 
     public static Display.Mode createMode(int width, int height, float refreshRate) {
-        return new Display.Mode(
-                NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate);
+        return createMode(width, height, refreshRate, new float[0]);
+    }
+
+    public static Display.Mode createMode(int width, int height, float refreshRate,
+            float[] alternativeRefreshRates) {
+        return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate,
+                alternativeRefreshRates);
     }
 
     public interface Listener {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1a62b9d..09c9aab 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -417,6 +417,7 @@
         mBlanker = blanker;
         mContext = context;
         mBrightnessSynchronizer = new BrightnessSynchronizer(context);
+        mBrightnessSynchronizer.startSynchronizing();
         mDisplayId = displayId;
 
         PowerManager pm =  context.getSystemService(PowerManager.class);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 9245f55..f657858 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -266,12 +266,27 @@
             boolean modesAdded = false;
             for (int i = 0; i < configs.length; i++) {
                 SurfaceControl.DisplayConfig config = configs[i];
+                List<Float> alternativeRefreshRates = new ArrayList<>();
+                for (int j = 0; j < configs.length; j++) {
+                    SurfaceControl.DisplayConfig other = configs[j];
+                    boolean isAlternative = j != i && other.width == config.width
+                            && other.height == config.height
+                            && other.refreshRate != config.refreshRate
+                            && other.configGroup == config.configGroup;
+                    if (isAlternative) {
+                        alternativeRefreshRates.add(configs[j].refreshRate);
+                    }
+                }
+                Collections.sort(alternativeRefreshRates);
+
                 // First, check to see if we've already added a matching mode. Since not all
                 // configuration options are exposed via Display.Mode, it's possible that we have
                 // multiple DisplayConfigs that would generate the same Display.Mode.
                 boolean existingMode = false;
-                for (int j = 0; j < records.size(); j++) {
-                    if (records.get(j).hasMatchingMode(config)) {
+                for (DisplayModeRecord record : records) {
+                    if (record.hasMatchingMode(config)
+                            && refreshRatesEquals(alternativeRefreshRates,
+                                    record.mMode.getAlternativeRefreshRates())) {
                         existingMode = true;
                         break;
                     }
@@ -282,9 +297,13 @@
                 // If we haven't already added a mode for this configuration to the new set of
                 // supported modes then check to see if we have one in the prior set of supported
                 // modes to reuse.
-                DisplayModeRecord record = findDisplayModeRecord(config);
+                DisplayModeRecord record = findDisplayModeRecord(config, alternativeRefreshRates);
                 if (record == null) {
-                    record = new DisplayModeRecord(config);
+                    float[] alternativeRates = new float[alternativeRefreshRates.size()];
+                    for (int j = 0; j < alternativeRates.length; j++) {
+                        alternativeRates[j] = alternativeRefreshRates.get(j);
+                    }
+                    record = new DisplayModeRecord(config, alternativeRates);
                     modesAdded = true;
                 }
                 records.add(record);
@@ -495,16 +514,31 @@
             return true;
         }
 
-        private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config) {
+        private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config,
+                List<Float> alternativeRefreshRates) {
             for (int i = 0; i < mSupportedModes.size(); i++) {
                 DisplayModeRecord record = mSupportedModes.valueAt(i);
-                if (record.hasMatchingMode(config)) {
+                if (record.hasMatchingMode(config)
+                        && refreshRatesEquals(alternativeRefreshRates,
+                                record.mMode.getAlternativeRefreshRates())) {
                     return record;
                 }
             }
             return null;
         }
 
+        private boolean refreshRatesEquals(List<Float> list, float[] array) {
+            if (list.size() != array.length) {
+                return false;
+            }
+            for (int i = 0; i < list.size(); i++) {
+                if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         @Override
         public void applyPendingDisplayDeviceInfoChangesLocked() {
             if (mHavePendingChanges) {
@@ -1032,8 +1066,10 @@
     private static final class DisplayModeRecord {
         public final Display.Mode mMode;
 
-        DisplayModeRecord(SurfaceControl.DisplayConfig config) {
-            mMode = createMode(config.width, config.height, config.refreshRate);
+        DisplayModeRecord(SurfaceControl.DisplayConfig config,
+                float[] alternativeRefreshRates) {
+            mMode = createMode(config.width, config.height, config.refreshRate,
+                    alternativeRefreshRates);
         }
 
         /**
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 5fddae5..d0cc8e71 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -88,79 +88,84 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        MESSAGE_FEATURE_ABORT,
-        MESSAGE_IMAGE_VIEW_ON,
-        MESSAGE_TUNER_STEP_INCREMENT,
-        MESSAGE_TUNER_STEP_DECREMENT,
-        MESSAGE_TUNER_DEVICE_STATUS,
-        MESSAGE_GIVE_TUNER_DEVICE_STATUS,
-        MESSAGE_RECORD_ON,
-        MESSAGE_RECORD_STATUS,
-        MESSAGE_RECORD_OFF,
-        MESSAGE_TEXT_VIEW_ON,
-        MESSAGE_RECORD_TV_SCREEN,
-        MESSAGE_GIVE_DECK_STATUS,
-        MESSAGE_DECK_STATUS,
-        MESSAGE_SET_MENU_LANGUAGE,
-        MESSAGE_CLEAR_ANALOG_TIMER,
-        MESSAGE_SET_ANALOG_TIMER,
-        MESSAGE_TIMER_STATUS,
-        MESSAGE_STANDBY,
-        MESSAGE_PLAY,
-        MESSAGE_DECK_CONTROL,
-        MESSAGE_TIMER_CLEARED_STATUS,
-        MESSAGE_USER_CONTROL_PRESSED,
-        MESSAGE_USER_CONTROL_RELEASED,
-        MESSAGE_GIVE_OSD_NAME,
-        MESSAGE_SET_OSD_NAME,
-        MESSAGE_SET_OSD_STRING,
-        MESSAGE_SET_TIMER_PROGRAM_TITLE,
-        MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
-        MESSAGE_GIVE_AUDIO_STATUS,
-        MESSAGE_SET_SYSTEM_AUDIO_MODE,
-        MESSAGE_REPORT_AUDIO_STATUS,
-        MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
-        MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
-        MESSAGE_ROUTING_CHANGE,
-        MESSAGE_ROUTING_INFORMATION,
-        MESSAGE_ACTIVE_SOURCE,
-        MESSAGE_GIVE_PHYSICAL_ADDRESS,
-        MESSAGE_REPORT_PHYSICAL_ADDRESS,
-        MESSAGE_REQUEST_ACTIVE_SOURCE,
-        MESSAGE_SET_STREAM_PATH,
-        MESSAGE_DEVICE_VENDOR_ID,
-        MESSAGE_VENDOR_COMMAND,
-        MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
-        MESSAGE_VENDOR_REMOTE_BUTTON_UP,
-        MESSAGE_GIVE_DEVICE_VENDOR_ID,
-        MESSAGE_MENU_REQUEST,
-        MESSAGE_MENU_STATUS,
-        MESSAGE_GIVE_DEVICE_POWER_STATUS,
-        MESSAGE_REPORT_POWER_STATUS,
-        MESSAGE_GET_MENU_LANGUAGE,
-        MESSAGE_SELECT_ANALOG_SERVICE,
-        MESSAGE_SELECT_DIGITAL_SERVICE,
-        MESSAGE_SET_DIGITAL_TIMER,
-        MESSAGE_CLEAR_DIGITAL_TIMER,
-        MESSAGE_SET_AUDIO_RATE,
-        MESSAGE_INACTIVE_SOURCE,
-        MESSAGE_CEC_VERSION,
-        MESSAGE_GET_CEC_VERSION,
-        MESSAGE_VENDOR_COMMAND_WITH_ID,
-        MESSAGE_CLEAR_EXTERNAL_TIMER,
-        MESSAGE_SET_EXTERNAL_TIMER,
-        MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
-        MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
-        MESSAGE_INITIATE_ARC,
-        MESSAGE_REPORT_ARC_INITIATED,
-        MESSAGE_REPORT_ARC_TERMINATED,
-        MESSAGE_REQUEST_ARC_INITIATION,
-        MESSAGE_REQUEST_ARC_TERMINATION,
-        MESSAGE_TERMINATE_ARC,
-        MESSAGE_CDC_MESSAGE,
-        MESSAGE_ABORT,
+            MESSAGE_FEATURE_ABORT,
+            MESSAGE_IMAGE_VIEW_ON,
+            MESSAGE_TUNER_STEP_INCREMENT,
+            MESSAGE_TUNER_STEP_DECREMENT,
+            MESSAGE_TUNER_DEVICE_STATUS,
+            MESSAGE_GIVE_TUNER_DEVICE_STATUS,
+            MESSAGE_RECORD_ON,
+            MESSAGE_RECORD_STATUS,
+            MESSAGE_RECORD_OFF,
+            MESSAGE_TEXT_VIEW_ON,
+            MESSAGE_RECORD_TV_SCREEN,
+            MESSAGE_GIVE_DECK_STATUS,
+            MESSAGE_DECK_STATUS,
+            MESSAGE_SET_MENU_LANGUAGE,
+            MESSAGE_CLEAR_ANALOG_TIMER,
+            MESSAGE_SET_ANALOG_TIMER,
+            MESSAGE_TIMER_STATUS,
+            MESSAGE_STANDBY,
+            MESSAGE_PLAY,
+            MESSAGE_DECK_CONTROL,
+            MESSAGE_TIMER_CLEARED_STATUS,
+            MESSAGE_USER_CONTROL_PRESSED,
+            MESSAGE_USER_CONTROL_RELEASED,
+            MESSAGE_GIVE_OSD_NAME,
+            MESSAGE_SET_OSD_NAME,
+            MESSAGE_SET_OSD_STRING,
+            MESSAGE_SET_TIMER_PROGRAM_TITLE,
+            MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+            MESSAGE_GIVE_AUDIO_STATUS,
+            MESSAGE_SET_SYSTEM_AUDIO_MODE,
+            MESSAGE_REPORT_AUDIO_STATUS,
+            MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
+            MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
+            MESSAGE_ROUTING_CHANGE,
+            MESSAGE_ROUTING_INFORMATION,
+            MESSAGE_ACTIVE_SOURCE,
+            MESSAGE_GIVE_PHYSICAL_ADDRESS,
+            MESSAGE_REPORT_PHYSICAL_ADDRESS,
+            MESSAGE_REQUEST_ACTIVE_SOURCE,
+            MESSAGE_SET_STREAM_PATH,
+            MESSAGE_DEVICE_VENDOR_ID,
+            MESSAGE_VENDOR_COMMAND,
+            MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
+            MESSAGE_VENDOR_REMOTE_BUTTON_UP,
+            MESSAGE_GIVE_DEVICE_VENDOR_ID,
+            MESSAGE_MENU_REQUEST,
+            MESSAGE_MENU_STATUS,
+            MESSAGE_GIVE_DEVICE_POWER_STATUS,
+            MESSAGE_REPORT_POWER_STATUS,
+            MESSAGE_GET_MENU_LANGUAGE,
+            MESSAGE_SELECT_ANALOG_SERVICE,
+            MESSAGE_SELECT_DIGITAL_SERVICE,
+            MESSAGE_SET_DIGITAL_TIMER,
+            MESSAGE_CLEAR_DIGITAL_TIMER,
+            MESSAGE_SET_AUDIO_RATE,
+            MESSAGE_INACTIVE_SOURCE,
+            MESSAGE_CEC_VERSION,
+            MESSAGE_GET_CEC_VERSION,
+            MESSAGE_VENDOR_COMMAND_WITH_ID,
+            MESSAGE_CLEAR_EXTERNAL_TIMER,
+            MESSAGE_SET_EXTERNAL_TIMER,
+            MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
+            MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
+            MESSAGE_GIVE_FEATURES,
+            MESSAGE_REPORT_FEATURES,
+            MESSAGE_REQUEST_CURRENT_LATENCY,
+            MESSAGE_REPORT_CURRENT_LATENCY,
+            MESSAGE_INITIATE_ARC,
+            MESSAGE_REPORT_ARC_INITIATED,
+            MESSAGE_REPORT_ARC_TERMINATED,
+            MESSAGE_REQUEST_ARC_INITIATION,
+            MESSAGE_REQUEST_ARC_TERMINATION,
+            MESSAGE_TERMINATE_ARC,
+            MESSAGE_CDC_MESSAGE,
+            MESSAGE_ABORT,
     })
-    public @interface FeatureOpcode {}
+    public @interface FeatureOpcode {
+    }
 
     static final int MESSAGE_FEATURE_ABORT = 0x00;
     static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
@@ -225,6 +230,10 @@
     static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
     static final int MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3;
     static final int MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4;
+    static final int MESSAGE_GIVE_FEATURES = 0xA5;
+    static final int MESSAGE_REPORT_FEATURES = 0xA6;
+    static final int MESSAGE_REQUEST_CURRENT_LATENCY = 0xA7;
+    static final int MESSAGE_REPORT_CURRENT_LATENCY = 0xA8;
     static final int MESSAGE_INITIATE_ARC = 0xC0;
     static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1;
     static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2;
@@ -501,6 +510,35 @@
     static final int VERSION_1_4 = 0x05;
     static final int VERSION_2_0 = 0x06;
 
+    static final int ALL_DEVICE_TYPES_TV = 7;
+    static final int ALL_DEVICE_TYPES_RECORDER = 6;
+    static final int ALL_DEVICE_TYPES_TUNER = 5;
+    static final int ALL_DEVICE_TYPES_PLAYBACK = 4;
+    static final int ALL_DEVICE_TYPES_AUDIO_SYSTEM = 3;
+    static final int ALL_DEVICE_TYPES_SWITCH = 2;
+
+    static final int DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN = 6;
+    static final int DEVICE_FEATURE_TV_SUPPORTS_SET_OSD_STRING = 5;
+    static final int DEVICE_FEATURE_SUPPORTS_DECK_CONTROL = 4;
+    static final int DEVICE_FEATURE_SUPPORTS_SET_AUDIO_RATE = 3;
+    static final int DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX = 2;
+    static final int DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX = 1;
+
+    static final int RC_PROFILE_TV = 0;
+    static final int RC_PROFILE_SOURCE = 1;
+
+    static final int RC_PROFILE_TV_NONE = 0x0;
+    static final int RC_PROFILE_TV_ONE = 0x2;
+    static final int RC_PROFILE_TV_TWO = 0x6;
+    static final int RC_PROFILE_TV_THREE = 0xA;
+    static final int RC_PROFILE_TV_FOUR = 0xE;
+
+    static final int RC_PROFILE_SOURCE_HANDLES_ROOT_MENU = 4;
+    static final int RC_PROFILE_SOURCE_HANDLES_SETUP_MENU = 3;
+    static final int RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU = 2;
+    static final int RC_PROFILE_SOURCE_HANDLES_TOP_MENU = 1;
+    static final int RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU = 0;
+
     private Constants() {
         /* cannot be instantiated */
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 38eb7fb..e7f302c 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -351,6 +351,8 @@
                 return handleRequestShortAudioDescriptor(message);
             case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
                 return handleReportShortAudioDescriptor(message);
+            case Constants.MESSAGE_GIVE_FEATURES:
+                return handleGiveFeatures(message);
             default:
                 return false;
         }
@@ -551,6 +553,33 @@
         return false;
     }
 
+    protected abstract int getRcProfile();
+
+    protected abstract List<Integer> getRcFeatures();
+
+    protected abstract List<Integer> getDeviceFeatures();
+
+    protected boolean handleGiveFeatures(HdmiCecMessage message) {
+        if (mService.getCecVersion() < Constants.VERSION_2_0) {
+            return false;
+        }
+
+        List<Integer> localDeviceTypes = new ArrayList<>();
+        for (HdmiCecLocalDevice localDevice : mService.getAllLocalDevices()) {
+            localDeviceTypes.add(localDevice.mDeviceType);
+        }
+
+
+        int rcProfile = getRcProfile();
+        List<Integer> rcFeatures = getRcFeatures();
+        List<Integer> deviceFeatures = getDeviceFeatures();
+
+        mService.sendCecCommand(
+                HdmiCecMessageBuilder.buildReportFeatures(mAddress, mService.getCecVersion(),
+                        localDeviceTypes, rcProfile, rcFeatures, deviceFeatures));
+        return true;
+    }
+
     @ServiceThreadOnly
     protected boolean handleStandby(HdmiCecMessage message) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 9dc0079..4110de6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -47,6 +47,8 @@
 import com.android.server.hdmi.HdmiUtils.CodecSad;
 import com.android.server.hdmi.HdmiUtils.DeviceConfig;
 
+import com.google.android.collect.Lists;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -176,6 +178,11 @@
     }
 
     @Override
+    protected List<Integer> getDeviceFeatures() {
+        return Lists.newArrayList(Constants.DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX);
+    }
+
+    @Override
     @ServiceThreadOnly
     void onHotplug(int portId, boolean connected) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 9605106..62b7d8f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -28,6 +28,8 @@
 import com.android.server.hdmi.Constants.LocalActivePort;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
+import com.google.android.collect.Lists;
+
 import java.util.List;
 
 /**
@@ -233,6 +235,24 @@
         // do nothing
     }
 
+    @Override
+    protected int getRcProfile() {
+        return Constants.RC_PROFILE_SOURCE;
+    }
+
+    @Override
+    protected List<Integer> getRcFeatures() {
+        return Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+                Constants.RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+                Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+                Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU);
+    }
+
+    @Override
+    protected List<Integer> getDeviceFeatures() {
+        return Lists.newArrayList();
+    }
+
     // Active source claiming needs to be handled in Service
     // since service can decide who will be the active source when the device supports
     // multiple device types in this method.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index c2e80ca..8cf6c97 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -51,6 +51,8 @@
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 
+import com.google.android.collect.Lists;
+
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -1479,6 +1481,22 @@
     }
 
     @Override
+    protected int getRcProfile() {
+        return Constants.RC_PROFILE_TV;
+    }
+
+    @Override
+    protected List<Integer> getRcFeatures() {
+        return Lists.newArrayList(Constants.RC_PROFILE_TV_NONE);
+    }
+
+    @Override
+    protected List<Integer> getDeviceFeatures() {
+        return Lists.newArrayList(Constants.DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX,
+                Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN);
+    }
+
+    @Override
     protected void sendStandby(int deviceId) {
         HdmiDeviceInfo targetDevice = mService.getHdmiCecNetwork().getDeviceInfo(deviceId);
         if (targetDevice == null) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index 7a6ce8d..c85fd50 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -18,6 +18,8 @@
 
 import android.annotation.Nullable;
 
+import com.android.server.hdmi.Constants.FeatureOpcode;
+
 import libcore.util.EmptyArray;
 
 import java.util.Arrays;
@@ -126,7 +128,7 @@
         return s.toString();
     }
 
-    private static String opcodeToString(int opcode) {
+    private static String opcodeToString(@FeatureOpcode int opcode) {
         switch (opcode) {
             case Constants.MESSAGE_FEATURE_ABORT:
                 return "Feature Abort";
@@ -264,6 +266,14 @@
                 return "Request ARC Initiation";
             case Constants.MESSAGE_REQUEST_ARC_TERMINATION:
                 return "Request ARC Termination";
+            case Constants.MESSAGE_GIVE_FEATURES:
+                return "Give Features";
+            case Constants.MESSAGE_REPORT_FEATURES:
+                return "Report Features";
+            case Constants.MESSAGE_REQUEST_CURRENT_LATENCY:
+                return "Request Current Latency";
+            case Constants.MESSAGE_REPORT_CURRENT_LATENCY:
+                return "Report Current Latency";
             case Constants.MESSAGE_TERMINATE_ARC:
                 return "Terminate ARC";
             case Constants.MESSAGE_CDC_MESSAGE:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 653323d..1a481b6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -16,10 +16,14 @@
 
 package com.android.server.hdmi;
 
+import android.hardware.hdmi.HdmiDeviceInfo;
+
 import com.android.server.hdmi.Constants.AudioCodec;
+import com.android.server.hdmi.Constants.CecVersion;
 
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * A helper class to build {@link HdmiCecMessage} from various cec commands.
@@ -688,6 +692,40 @@
         return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params);
     }
 
+    static HdmiCecMessage buildGiveFeatures(int src, int dest) {
+        return buildCommand(src, dest, Constants.MESSAGE_GIVE_FEATURES);
+    }
+
+    static HdmiCecMessage buildReportFeatures(int src, @CecVersion int cecVersion,
+            List<Integer> allDeviceTypes, int rcProfile, List<Integer> rcFeatures,
+            List<Integer> deviceFeatures) {
+        byte cecVersionByte = (byte) (cecVersion & 0xFF);
+        byte deviceTypes = 0;
+        for (Integer deviceType : allDeviceTypes) {
+            deviceTypes |= 1 << hdmiDeviceInfoDeviceTypeToShiftValue(deviceType);
+        }
+
+        byte rcProfileByte = 0;
+        rcProfileByte |= rcProfile << 6;
+        if (rcProfile == Constants.RC_PROFILE_SOURCE) {
+            for (Integer rcFeature : rcFeatures) {
+                rcProfileByte |= 1 << rcFeature;
+            }
+        } else {
+            byte rcProfileTv = (byte) (rcFeatures.get(0) & 0xFFFF);
+            rcProfileByte |= rcProfileTv;
+        }
+
+        byte deviceFeaturesByte = 0;
+        for (Integer deviceFeature : deviceFeatures) {
+            deviceFeaturesByte |= 1 << deviceFeature;
+        }
+
+        byte[] params = {cecVersionByte, deviceTypes, rcProfileByte, deviceFeaturesByte};
+        return buildCommand(src, Constants.ADDR_BROADCAST, Constants.MESSAGE_REPORT_FEATURES,
+                params);
+    }
+
     /***** Please ADD new buildXXX() methods above. ******/
 
     /**
@@ -738,4 +776,23 @@
                 (byte) (physicalAddress & 0xFF)
         };
     }
+
+    private static int hdmiDeviceInfoDeviceTypeToShiftValue(int deviceType) {
+        switch (deviceType) {
+            case HdmiDeviceInfo.DEVICE_TV:
+                return Constants.ALL_DEVICE_TYPES_TV;
+            case HdmiDeviceInfo.DEVICE_RECORDER:
+                return Constants.ALL_DEVICE_TYPES_RECORDER;
+            case HdmiDeviceInfo.DEVICE_TUNER:
+                return Constants.ALL_DEVICE_TYPES_TUNER;
+            case HdmiDeviceInfo.DEVICE_PLAYBACK:
+                return Constants.ALL_DEVICE_TYPES_PLAYBACK;
+            case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
+                return Constants.ALL_DEVICE_TYPES_AUDIO_SYSTEM;
+            case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH:
+                return Constants.ALL_DEVICE_TYPES_SWITCH;
+            default:
+                throw new IllegalArgumentException("Unhandled device type: " + deviceType);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index fe97f70..cdd9216 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -211,6 +211,17 @@
                 new OneByteRangeValidator(0x00, 0x06),
                 DEST_DIRECT);
 
+        // Messages for Feature Discovery.
+        addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, DEST_DIRECT);
+        addValidationInfo(Constants.MESSAGE_REPORT_FEATURES, new VariableLengthValidator(4, 14),
+                DEST_BROADCAST);
+
+        // Messages for Dynamic Auto Lipsync
+        addValidationInfo(Constants.MESSAGE_REQUEST_CURRENT_LATENCY, physicalAddressValidator,
+                DEST_BROADCAST);
+        addValidationInfo(Constants.MESSAGE_REPORT_CURRENT_LATENCY,
+                new VariableLengthValidator(4, 14), DEST_BROADCAST);
+
         // All Messages for the ARC have no parameters.
 
         // Messages for the Capability Discovery and Control.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b96aa3a..2fc9acb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1549,61 +1549,8 @@
         @Nullable
         public HdmiDeviceInfo getActiveSource() {
             enforceAccessPermission();
-            HdmiCecLocalDeviceTv tv = tv();
-            if (tv == null) {
-                if (isTvDevice()) {
-                    Slog.e(TAG, "Local tv device not available.");
-                    return null;
-                }
-                if (isPlaybackDevice()) {
-                    // if playback device itself is the active source,
-                    // return its own device info.
-                    if (playback() != null && playback().isActiveSource()) {
-                        return playback().getDeviceInfo();
-                    }
-                    // Otherwise get the active source and look for it from the device list
-                    ActiveSource activeSource = getLocalActiveSource();
-                    // If the physical address is not set yet, return null
-                    if (activeSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
-                        return null;
-                    }
-                    if (audioSystem() != null) {
-                        for (HdmiDeviceInfo info : mHdmiCecNetwork.getSafeCecDevicesLocked()) {
-                            if (info.getPhysicalAddress() == activeSource.physicalAddress) {
-                                return info;
-                            }
-                        }
-                    }
-                    // If the device info is not in the list yet, return a device info with minimum
-                    // information from mActiveSource.
-                    // If the Active Source has unregistered logical address, return with an
-                    // HdmiDeviceInfo built from physical address information only.
-                    return HdmiUtils.isValidAddress(activeSource.logicalAddress)
-                        ?
-                        new HdmiDeviceInfo(activeSource.logicalAddress,
-                            activeSource.physicalAddress,
-                            pathToPortId(activeSource.physicalAddress),
-                            HdmiUtils.getTypeFromAddress(activeSource.logicalAddress).get(0), 0,
-                            HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress))
-                        :
-                            new HdmiDeviceInfo(activeSource.physicalAddress,
-                                pathToPortId(activeSource.physicalAddress));
 
-                }
-                return null;
-            }
-            ActiveSource activeSource = tv.getActiveSource();
-            if (activeSource.isValid()) {
-                return new HdmiDeviceInfo(activeSource.logicalAddress,
-                        activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID,
-                        HdmiDeviceInfo.DEVICE_INACTIVE, 0, "");
-            }
-            int activePath = tv.getActivePath();
-            if (activePath != HdmiDeviceInfo.PATH_INVALID) {
-                HdmiDeviceInfo info = mHdmiCecNetwork.getSafeDeviceInfoByPath(activePath);
-                return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId());
-            }
-            return null;
+            return HdmiControlService.this.getActiveSource();
         }
 
         @Override
@@ -2435,6 +2382,39 @@
         source.queryDisplayStatus(callback);
     }
 
+    protected HdmiDeviceInfo getActiveSource() {
+        // If a the device is a playback device that is the current active source, return the
+        // local device info
+        if (playback() != null && playback().isActiveSource()) {
+            return playback().getDeviceInfo();
+        }
+
+        // Otherwise get the active source and look for it from the device list
+        ActiveSource activeSource = getLocalActiveSource();
+
+        if (activeSource.isValid()) {
+            HdmiDeviceInfo activeSourceInfo = mHdmiCecNetwork.getSafeCecDeviceInfo(
+                    activeSource.logicalAddress);
+            if (activeSourceInfo != null) {
+                return activeSourceInfo;
+            }
+
+            return new HdmiDeviceInfo(activeSource.physicalAddress,
+                    pathToPortId(activeSource.physicalAddress));
+        }
+
+        if (tv() != null) {
+            int activePath = tv().getActivePath();
+            if (activePath != HdmiDeviceInfo.PATH_INVALID) {
+                HdmiDeviceInfo info = mHdmiCecNetwork.getSafeDeviceInfoByPath(activePath);
+                return (info != null) ? info : new HdmiDeviceInfo(activePath,
+                        tv().getActivePortId());
+            }
+        }
+
+        return null;
+    }
+
     private void addHdmiControlStatusChangeListener(
             final IHdmiControlStatusChangeListener listener) {
         final HdmiControlStatusChangeListenerRecord record =
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 51e6cf4..d08980c 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -48,6 +48,8 @@
     private static final float DEFAULT_PRECISION_X = 1.0f;
     private static final float DEFAULT_PRECISION_Y = 1.0f;
     private static final int DEFAULT_EDGE_FLAGS = 0;
+    private static final int DEFAULT_BUTTON_STATE = 0;
+    private static final int DEFAULT_FLAGS = 0;
 
     private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
             put("keyboard", InputDevice.SOURCE_KEYBOARD);
@@ -110,15 +112,28 @@
      */
     private void injectMotionEvent(int inputSource, int action, long downTime, long when,
             float x, float y, float pressure, int displayId) {
-        MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure,
-                DEFAULT_SIZE, DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
-                getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
-        event.setSource(inputSource);
+        final int pointerCount = 1;
+        MotionEvent.PointerProperties[] pointerProperties =
+                new MotionEvent.PointerProperties[pointerCount];
+        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
+        for (int i = 0; i < pointerCount; i++) {
+            pointerProperties[i] = new MotionEvent.PointerProperties();
+            pointerProperties[i].id = i;
+            pointerProperties[i].toolType = getToolType(inputSource);
+            pointerCoords[i] = new MotionEvent.PointerCoords();
+            pointerCoords[i].x = x;
+            pointerCoords[i].y = y;
+            pointerCoords[i].pressure = pressure;
+            pointerCoords[i].size = DEFAULT_SIZE;
+        }
         if (displayId == INVALID_DISPLAY
                 && (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
             displayId = DEFAULT_DISPLAY;
         }
-        event.setDisplayId(displayId);
+        MotionEvent event = MotionEvent.obtain(downTime, when, action, pointerCount,
+                pointerProperties, pointerCoords, DEFAULT_META_STATE, DEFAULT_BUTTON_STATE,
+                DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource),
+                DEFAULT_EDGE_FLAGS, inputSource, displayId, DEFAULT_FLAGS);
         InputManager.getInstance().injectInputEvent(event,
                 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
     }
@@ -131,6 +146,25 @@
         return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
     }
 
+    private int getToolType(int inputSource) {
+        switch(inputSource) {
+            case InputDevice.SOURCE_MOUSE:
+            case InputDevice.SOURCE_MOUSE_RELATIVE:
+            case InputDevice.SOURCE_TRACKBALL:
+                return MotionEvent.TOOL_TYPE_MOUSE;
+
+            case InputDevice.SOURCE_STYLUS:
+            case InputDevice.SOURCE_BLUETOOTH_STYLUS:
+                return MotionEvent.TOOL_TYPE_STYLUS;
+
+            case InputDevice.SOURCE_TOUCHPAD:
+            case InputDevice.SOURCE_TOUCHSCREEN:
+            case InputDevice.SOURCE_TOUCH_NAVIGATION:
+                return MotionEvent.TOOL_TYPE_FINGER;
+        }
+        return MotionEvent.TOOL_TYPE_UNKNOWN;
+    }
+
     @Override
     public final int onCommand(String cmd) {
         String arg = cmd;
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index bd2676e..26bf6c1 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -17,7 +17,7 @@
 package com.android.server.location;
 
 import android.annotation.Nullable;
-import android.location.Location;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Binder;
 import android.os.Bundle;
@@ -27,8 +27,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicReference;
@@ -56,13 +54,7 @@
          * Called when a provider has a new location available. May be invoked from any thread. Will
          * be invoked with a cleared binder identity.
          */
-        void onReportLocation(Location location);
-
-        /**
-         * Called when a provider has a new location available. May be invoked from any thread. Will
-         * be invoked with a cleared binder identity.
-         */
-        void onReportLocation(List<Location> locations);
+        void onReportLocation(LocationResult locationResult);
     }
 
     /**
@@ -302,33 +294,12 @@
     /**
      * Call this method to report a new location.
      */
-    protected void reportLocation(Location location) {
+    protected void reportLocation(LocationResult locationResult) {
         Listener listener = mInternalState.get().listener;
         if (listener != null) {
             final long identity = Binder.clearCallingIdentity();
             try {
-                // copy location so if provider makes further changes they do not propagate
-                listener.onReportLocation(new Location(location));
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    /**
-     * Call this method to report a new location.
-     */
-    protected void reportLocation(List<Location> locations) {
-        Listener listener = mInternalState.get().listener;
-        if (listener != null) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                // copy location so if provider makes further changes they do not propagate
-                ArrayList<Location> copy = new ArrayList<>(locations.size());
-                for (Location location : locations) {
-                    copy.add(new Location(location));
-                }
-                listener.onReportLocation(copy);
+                listener.onReportLocation(Objects.requireNonNull(locationResult));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -349,6 +320,23 @@
     protected abstract void onSetRequest(ProviderRequest request);
 
     /**
+     * Requests that any applicable locations are flushed. Normally only relevant for batched
+     * locations.
+     */
+    public final void flush(Runnable listener) {
+        // all calls into the provider must be moved onto the provider thread to prevent deadlock
+        mExecutor.execute(() -> onFlush(listener));
+    }
+
+    /**
+     * Always invoked on the provider executor. The callback must always be invoked exactly once
+     * for every invocation, and should only be invoked after
+     * {@link #reportLocation(LocationResult)} has been called for every flushed location. If no
+     * locations are flushed, the callback may be invoked immediately.
+     */
+    protected abstract void onFlush(Runnable callback);
+
+    /**
      * Sends an extra command to the provider for it to interpret as it likes.
      */
     public final void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index ecdd429..c2bfc51 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.location.Location;
+import android.location.LocationResult;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,11 @@
     @GuardedBy("this")
     @Nullable private Location mCachedCoarseLocation;
 
+    @GuardedBy("this")
+    @Nullable private LocationResult mCachedFineLocationResult;
+    @GuardedBy("this")
+    @Nullable private LocationResult mCachedCoarseLocationResult;
+
     public LocationFudger(float accuracyM) {
         this(accuracyM, SystemClock.elapsedRealtimeClock(), new SecureRandom());
     }
@@ -100,6 +106,28 @@
     }
 
     /**
+     * Coarsens a LocationResult by coarsening every location within the location result with
+     * {@link #createCoarse(Location)}.
+     */
+    public LocationResult createCoarse(LocationResult fineLocationResult) {
+        synchronized (this) {
+            if (fineLocationResult == mCachedFineLocationResult
+                    || fineLocationResult == mCachedCoarseLocationResult) {
+                return mCachedCoarseLocationResult;
+            }
+        }
+
+        LocationResult coarseLocationResult = fineLocationResult.map(this::createCoarse);
+
+        synchronized (this) {
+            mCachedFineLocationResult = fineLocationResult;
+            mCachedCoarseLocationResult = coarseLocationResult;
+        }
+
+        return coarseLocationResult;
+    }
+
+    /**
      * Create a coarse location using two technique, random offsets and snap-to-grid.
      *
      * First we add a random offset to mitigate against detecting grid transitions. Without a random
@@ -154,7 +182,7 @@
             mCachedCoarseLocation = coarse;
         }
 
-        return mCachedCoarseLocation;
+        return coarse;
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 18185ae..d225f968 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -32,6 +32,7 @@
 
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
+import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,7 +48,6 @@
 import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
 import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
@@ -219,6 +219,10 @@
     private volatile @Nullable GnssManagerService mGnssManagerService = null;
     private GeocoderProxy mGeocodeProvider;
 
+    private final Object mDeprecatedGnssBatchingLock = new Object();
+    @GuardedBy("mDeprecatedGnssBatchingLock")
+    private @Nullable ILocationListener mDeprecatedGnssBatchingListener;
+
     @GuardedBy("mLock")
     private String mExtraLocationControllerPackage;
     @GuardedBy("mLock")
@@ -245,7 +249,7 @@
         // set up passive provider first since it will be required for all other location providers,
         // which are loaded later once the system is ready.
         mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
-        addLocationProviderManager(mPassiveManager, new PassiveProvider(mContext));
+        addLocationProviderManager(mPassiveManager, new PassiveLocationProvider(mContext));
 
         // TODO: load the gps provider here as well, which will require refactoring
 
@@ -320,7 +324,7 @@
     }
 
     void onSystemThirdPartyAppsCanStart() {
-        LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
+        ProxyLocationProvider networkProvider = ProxyLocationProvider.createAndRegister(
                 mContext,
                 NETWORK_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableNetworkLocationOverlay,
@@ -339,7 +343,7 @@
                 MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
                 "Unable to find a direct boot aware fused location provider");
 
-        LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
+        ProxyLocationProvider fusedProvider = ProxyLocationProvider.createAndRegister(
                 mContext,
                 FUSED_LOCATION_SERVICE_ACTION,
                 com.android.internal.R.bool.config_enableFusedLocationOverlay,
@@ -404,7 +408,7 @@
                     Integer.parseInt(fragments[8]) /* powerRequirement */,
                     Integer.parseInt(fragments[9]) /* accuracy */);
             getOrAddLocationProviderManager(name).setMockProvider(
-                    new MockProvider(properties, CallerIdentity.fromContext(mContext)));
+                    new MockLocationProvider(properties, CallerIdentity.fromContext(mContext)));
         }
     }
 
@@ -442,40 +446,63 @@
     }
 
     @Override
-    public void setGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
-            String attributionTag) {
-        if (mGnssManagerService != null) {
-            mGnssManagerService.setGnssBatchingCallback(callback, packageName, attributionTag);
-        }
-    }
+    public void startGnssBatch(long periodNanos, ILocationListener listener, String packageName,
+            String attributionTag, String listenerId) {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
 
-    @Override
-    public void removeGnssBatchingCallback() {
-        if (mGnssManagerService != null) {
-            mGnssManagerService.removeGnssBatchingCallback();
+        if (mGnssManagerService == null) {
+            return;
         }
-    }
 
-    @Override
-    public void startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName,
-            String attributionTag) {
-        if (mGnssManagerService != null) {
-            mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull, packageName,
-                    attributionTag);
+        long intervalMs = NANOSECONDS.toMillis(periodNanos);
+
+        synchronized (mDeprecatedGnssBatchingLock) {
+            stopGnssBatch();
+
+            registerLocationListener(
+                    GPS_PROVIDER,
+                    new LocationRequest.Builder(intervalMs)
+                            .setMaxUpdateDelayMillis(
+                                    intervalMs * mGnssManagerService.getGnssBatchSize())
+                            .setHiddenFromAppOps(true)
+                            .build(),
+                    listener,
+                    packageName,
+                    attributionTag,
+                    listenerId);
+            mDeprecatedGnssBatchingListener = listener;
         }
     }
 
     @Override
     public void flushGnssBatch() {
-        if (mGnssManagerService != null) {
-            mGnssManagerService.flushGnssBatch();
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
+
+        if (mGnssManagerService == null) {
+            return;
+        }
+
+        synchronized (mDeprecatedGnssBatchingLock) {
+            if (mDeprecatedGnssBatchingListener != null) {
+                requestListenerFlush(GPS_PROVIDER, mDeprecatedGnssBatchingListener, 0);
+            }
         }
     }
 
     @Override
     public void stopGnssBatch() {
-        if (mGnssManagerService != null) {
-            mGnssManagerService.stopGnssBatch();
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
+
+        if (mGnssManagerService == null) {
+            return;
+        }
+
+        synchronized (mDeprecatedGnssBatchingLock) {
+            if (mDeprecatedGnssBatchingListener != null) {
+                ILocationListener listener = mDeprecatedGnssBatchingListener;
+                mDeprecatedGnssBatchingListener = null;
+                unregisterLocationListener(listener);
+            }
         }
     }
 
@@ -673,6 +700,25 @@
     }
 
     @Override
+    public void requestListenerFlush(String provider, ILocationListener listener, int requestCode) {
+        LocationProviderManager manager = getLocationProviderManager(provider);
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + provider + "\" does not exist");
+
+        manager.flush(Objects.requireNonNull(listener), requestCode);
+    }
+
+    @Override
+    public void requestPendingIntentFlush(String provider, PendingIntent pendingIntent,
+            int requestCode) {
+        LocationProviderManager manager = getLocationProviderManager(provider);
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + provider + "\" does not exist");
+
+        manager.flush(Objects.requireNonNull(pendingIntent), requestCode);
+    }
+
+    @Override
     public void unregisterLocationListener(ILocationListener listener) {
         for (LocationProviderManager manager : mProviderManagers) {
             manager.unregisterLocationRequest(listener);
@@ -1037,7 +1083,7 @@
         }
 
         getOrAddLocationProviderManager(provider).setMockProvider(
-                new MockProvider(properties, identity));
+                new MockLocationProvider(properties, identity));
     }
 
     @Override
@@ -1218,13 +1264,6 @@
                 mGnssManagerService.sendNiResponse(notifId, userResponse);
             }
         }
-
-        @Override
-        public void reportGnssBatchLocations(List<Location> locations) {
-            if (mGnssManagerService != null) {
-                mGnssManagerService.onReportLocation(locations);
-            }
-        }
     }
 
     private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index f8d1195..b0b5575 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -20,7 +20,9 @@
 import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
 import static android.location.LocationManager.FUSED_PROVIDER;
 import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
 import static android.location.LocationManager.KEY_LOCATION_CHANGED;
+import static android.location.LocationManager.KEY_LOCATION_RESULT;
 import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
 import static android.location.LocationManager.PASSIVE_PROVIDER;
 import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
@@ -52,6 +54,7 @@
 import android.location.LocationManagerInternal;
 import android.location.LocationManagerInternal.ProviderEnabledListener;
 import android.location.LocationRequest;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Binder;
 import android.os.Build;
@@ -112,8 +115,8 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
 import java.util.Objects;
+import java.util.function.Predicate;
 
 class LocationProviderManager extends
         ListenerMultiplexer<Object, LocationProviderManager.LocationTransport,
@@ -155,8 +158,9 @@
 
     protected interface LocationTransport {
 
-        void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback)
-                throws Exception;
+        void deliverOnLocationChanged(LocationResult locationResult,
+                @Nullable Runnable onCompleteCallback) throws Exception;
+        void deliverOnFlushComplete(int requestCode) throws Exception;
     }
 
     protected interface ProviderTransport {
@@ -174,9 +178,14 @@
         }
 
         @Override
-        public void deliverOnLocationChanged(Location location,
+        public void deliverOnLocationChanged(LocationResult locationResult,
                 @Nullable Runnable onCompleteCallback) throws RemoteException {
-            mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
+            mListener.onLocationChanged(locationResult, SingleUseCallback.wrap(onCompleteCallback));
+        }
+
+        @Override
+        public void deliverOnFlushComplete(int requestCode) throws RemoteException {
+            mListener.onFlushComplete(requestCode);
         }
 
         @Override
@@ -198,12 +207,26 @@
         }
 
         @Override
-        public void deliverOnLocationChanged(Location location,
+        public void deliverOnLocationChanged(LocationResult locationResult,
                 @Nullable Runnable onCompleteCallback)
                 throws PendingIntent.CanceledException {
-            mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_LOCATION_CHANGED, location),
+            mPendingIntent.send(
+                    mContext,
+                    0,
+                    new Intent()
+                            .putExtra(KEY_LOCATION_CHANGED, locationResult.getLastLocation())
+                            .putExtra(KEY_LOCATION_RESULT, locationResult),
                     onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
-                            : null, null, null,
+                            : null,
+                    null,
+                    null,
+                    PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+        }
+
+        @Override
+        public void deliverOnFlushComplete(int requestCode) throws PendingIntent.CanceledException {
+            mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_FLUSH_COMPLETE, requestCode),
+                    null, null, null,
                     PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
         }
 
@@ -225,13 +248,20 @@
         }
 
         @Override
-        public void deliverOnLocationChanged(Location location,
+        public void deliverOnLocationChanged(@Nullable LocationResult locationResult,
                 @Nullable Runnable onCompleteCallback)
                 throws RemoteException {
             // ILocationCallback doesn't currently support completion callbacks
             Preconditions.checkState(onCompleteCallback == null);
-            mCallback.onLocation(location);
+            if (locationResult != null) {
+                mCallback.onLocation(locationResult.getLastLocation());
+            } else {
+                mCallback.onLocation(null);
+            }
         }
+
+        @Override
+        public void deliverOnFlushComplete(int requestCode) {}
     }
 
     protected abstract class Registration extends RemoteListenerRegistration<LocationRequest,
@@ -377,6 +407,14 @@
             return mPermitted;
         }
 
+        public final void flush(int requestCode) {
+            // when the flush callback is invoked, we are guaranteed that locations have been
+            // queued on our executor, so by running the listener callback on the same executor it
+            // should be guaranteed that those locations will be delivered before the flush callback
+            mProvider.flush(() -> executeOperation(
+                    listener -> listener.deliverOnFlushComplete(requestCode)));
+        }
+
         @Override
         protected final LocationProviderManager getOwner() {
             return LocationProviderManager.this;
@@ -539,7 +577,7 @@
 
         @GuardedBy("mLock")
         abstract @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
-                Location fineLocation);
+                LocationResult fineLocationResult);
 
         @Override
         public String toString() {
@@ -668,7 +706,7 @@
                             getRequest().isLocationSettingsIgnored(),
                             maxLocationAgeMs);
                     if (lastLocation != null) {
-                        executeOperation(acceptLocationChange(lastLocation));
+                        executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
                     }
                 }
             }
@@ -677,22 +715,21 @@
         @Override
         public void onAlarm() {
             if (D) {
-                Log.d(TAG, "removing " + getIdentity() + " from " + mName
-                        + " provider due to expiration at " + TimeUtils.formatRealtime(
-                        mExpirationRealtimeMs));
+                Log.d(TAG, mName + " provider registration " + getIdentity()
+                        + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
             }
 
             synchronized (mLock) {
-                remove();
                 // no need to remove alarm after it's fired
                 mExpirationRealtimeMs = Long.MAX_VALUE;
+                remove();
             }
         }
 
         @GuardedBy("mLock")
         @Override
         @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
-                Location fineLocation) {
+                LocationResult fineLocationResult) {
             if (Build.IS_DEBUGGABLE) {
                 Preconditions.checkState(Thread.holdsLock(mLock));
             }
@@ -700,30 +737,52 @@
             // check expiration time - alarm is not guaranteed to go off at the right time,
             // especially for short intervals
             if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+                if (D) {
+                    Log.d(TAG, mName + " provider registration " + getIdentity()
+                            + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
+                }
                 remove();
                 return null;
             }
 
-            Location location = Objects.requireNonNull(
-                    getPermittedLocation(fineLocation, getPermissionLevel()));
+            LocationResult permittedLocationResult = Objects.requireNonNull(
+                    getPermittedLocationResult(fineLocationResult, getPermissionLevel()));
 
-            Location lastDeliveredLocation = getLastDeliveredLocation();
-            if (lastDeliveredLocation != null) {
-                // check fastest interval
-                long deltaMs = location.getElapsedRealtimeMillis()
-                        - lastDeliveredLocation.getElapsedRealtimeMillis();
-                long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
-                        * getRequest().getIntervalMillis()), MAX_FASTEST_INTERVAL_JITTER_MS);
-                if (deltaMs < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
-                    return null;
-                }
+            LocationResult locationResult = permittedLocationResult.filter(
+                    new Predicate<Location>() {
+                        private Location mPreviousLocation = getLastDeliveredLocation();
 
-                // check smallest displacement
-                double smallestDisplacementM = getRequest().getMinUpdateDistanceMeters();
-                if (smallestDisplacementM > 0.0 && location.distanceTo(lastDeliveredLocation)
-                        <= smallestDisplacementM) {
-                    return null;
-                }
+                        @Override
+                        public boolean test(Location location) {
+                            if (mPreviousLocation != null) {
+                                // check fastest interval
+                                long deltaMs = location.getElapsedRealtimeMillis()
+                                        - mPreviousLocation.getElapsedRealtimeMillis();
+                                long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
+                                                * getRequest().getIntervalMillis()),
+                                        MAX_FASTEST_INTERVAL_JITTER_MS);
+                                if (deltaMs
+                                        < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
+                                    return false;
+                                }
+
+                                // check smallest displacement
+                                double smallestDisplacementM =
+                                        getRequest().getMinUpdateDistanceMeters();
+                                if (smallestDisplacementM > 0.0 && location.distanceTo(
+                                        mPreviousLocation)
+                                        <= smallestDisplacementM) {
+                                    return false;
+                                }
+                            }
+
+                            mPreviousLocation = location;
+                            return true;
+                        }
+                    });
+
+            if (locationResult == null) {
+                return null;
             }
 
             // note app ops
@@ -742,10 +801,17 @@
 
                 @Override
                 public void onPreExecute() {
-                    mUseWakeLock = !location.isFromMockProvider();
+                    mUseWakeLock = false;
+                    final int size = locationResult.size();
+                    for (int i = 0; i < size; ++i) {
+                        if (!locationResult.get(i).isFromMockProvider()) {
+                            mUseWakeLock = true;
+                            break;
+                        }
+                    }
 
                     // update last delivered location
-                    setLastDeliveredLocation(location);
+                    setLastDeliveredLocation(locationResult.getLastLocation());
 
                     // don't acquire a wakelock for mock locations to prevent abuse
                     if (mUseWakeLock) {
@@ -757,16 +823,17 @@
                 public void operate(LocationTransport listener) throws Exception {
                     // if delivering to the same process, make a copy of the location first (since
                     // location is mutable)
-                    Location deliveryLocation;
+                    LocationResult deliverLocationResult;
                     if (getIdentity().getPid() == Process.myPid()) {
-                        deliveryLocation = new Location(location);
+                        deliverLocationResult = locationResult.deepCopy();
                     } else {
-                        deliveryLocation = location;
+                        deliverLocationResult = locationResult;
                     }
 
-                    listener.deliverOnLocationChanged(deliveryLocation,
+                    listener.deliverOnLocationChanged(deliverLocationResult,
                             mUseWakeLock ? mWakeLock::release : null);
-                    mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
+                    mLocationEventLog.logProviderDeliveredLocations(mName, locationResult.size(),
+                            getIdentity());
                 }
 
                 @Override
@@ -781,8 +848,8 @@
                         boolean remove = ++mNumLocationsDelivered >= getRequest().getMaxUpdates();
                         if (remove) {
                             if (D) {
-                                Log.d(TAG, "removing " + getIdentity() + " from " + mName
-                                        + " provider due to number of updates");
+                                Log.d(TAG, mName + " provider registration " + getIdentity()
+                                        + " finished after " + mNumLocationsDelivered + " updates");
                             }
 
                             synchronized (mLock) {
@@ -848,14 +915,14 @@
             onTransportFailure(exception);
         }
 
-        private void onTransportFailure(Exception exception) {
-            if (exception instanceof RemoteException) {
-                Log.w(TAG, "registration " + this + " removed", exception);
+        private void onTransportFailure(Exception e) {
+            if (e instanceof RemoteException) {
+                Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
                 synchronized (mLock) {
                     remove();
                 }
             } else {
-                throw new AssertionError(exception);
+                throw new AssertionError(e);
             }
         }
 
@@ -863,7 +930,7 @@
         public void binderDied() {
             try {
                 if (D) {
-                    Log.d(TAG, mName + " provider client died: " + getIdentity());
+                    Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
                 }
 
                 synchronized (mLock) {
@@ -910,19 +977,23 @@
             onTransportFailure(exception);
         }
 
-        private void onTransportFailure(Exception exception) {
-            if (exception instanceof PendingIntent.CanceledException) {
-                Log.w(TAG, "registration " + this + " removed", exception);
+        private void onTransportFailure(Exception e) {
+            if (e instanceof RemoteException) {
+                Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
                 synchronized (mLock) {
                     remove();
                 }
             } else {
-                throw new AssertionError(exception);
+                throw new AssertionError(e);
             }
         }
 
         @Override
         public void onCancelled(PendingIntent intent) {
+            if (D) {
+                Log.d(TAG, mName + " provider registration " + getIdentity() + " cancelled");
+            }
+
             synchronized (mLock) {
                 remove();
             }
@@ -932,19 +1003,11 @@
     protected final class GetCurrentLocationListenerRegistration extends Registration implements
             IBinder.DeathRecipient, OnAlarmListener {
 
-        private volatile LocationTransport mTransport;
-
         private long mExpirationRealtimeMs = Long.MAX_VALUE;
 
         protected GetCurrentLocationListenerRegistration(LocationRequest request,
                 CallerIdentity identity, LocationTransport transport, int permissionLevel) {
             super(request, identity, transport, permissionLevel);
-            mTransport = transport;
-        }
-
-        @Override
-        protected void onListenerUnregister() {
-            mTransport = null;
         }
 
         @GuardedBy("mLock")
@@ -988,45 +1051,41 @@
                     getRequest().isLocationSettingsIgnored(),
                     MAX_CURRENT_LOCATION_AGE_MS);
             if (lastLocation != null) {
-                executeOperation(acceptLocationChange(lastLocation));
+                executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
             }
         }
 
         @GuardedBy("mLock")
         @Override
         protected void onProviderListenerInactive() {
-            if (!getRequest().isLocationSettingsIgnored()) {
-                // if we go inactive for any reason, fail immediately
-                executeOperation(acceptLocationChange(null));
-            }
+            // if we go inactive for any reason, fail immediately
+            executeOperation(acceptLocationChange(null));
         }
 
         void deliverNull() {
             synchronized (mLock) {
-                executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(null));
+                executeOperation(acceptLocationChange(null));
             }
         }
 
         @Override
         public void onAlarm() {
             if (D) {
-                Log.d(TAG, "removing " + getIdentity() + " from " + mName
-                        + " provider due to expiration at " + TimeUtils.formatRealtime(
-                        mExpirationRealtimeMs));
+                Log.d(TAG, mName + " provider registration " + getIdentity()
+                        + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
             }
 
             synchronized (mLock) {
                 // no need to remove alarm after it's fired
                 mExpirationRealtimeMs = Long.MAX_VALUE;
-
-                deliverNull();
+                executeOperation(acceptLocationChange(null));
             }
         }
 
         @GuardedBy("mLock")
         @Override
         @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
-                @Nullable Location fineLocation) {
+                @Nullable LocationResult fineLocationResult) {
             if (Build.IS_DEBUGGABLE) {
                 Preconditions.checkState(Thread.holdsLock(mLock));
             }
@@ -1034,44 +1093,79 @@
             // check expiration time - alarm is not guaranteed to go off at the right time,
             // especially for short intervals
             if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
-                fineLocation = null;
+                if (D) {
+                    Log.d(TAG, mName + " provider registration " + getIdentity()
+                            + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
+                }
+                fineLocationResult = null;
             }
 
             // lastly - note app ops
-            if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
-                    getIdentity())) {
+            if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow(
+                    LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) {
                 if (D) {
                     Log.w(TAG, "noteOp denied for " + getIdentity());
                 }
-                fineLocation = null;
+                fineLocationResult = null;
             }
 
-            Location location = getPermittedLocation(fineLocation, getPermissionLevel());
+            if (fineLocationResult != null) {
+                fineLocationResult = fineLocationResult.asLastLocationResult();
+            }
+
+            LocationResult locationResult = getPermittedLocationResult(fineLocationResult,
+                    getPermissionLevel());
 
             // deliver location
-            return listener -> {
-                // if delivering to the same process, make a copy of the location first (since
-                // location is mutable)
-                Location deliveryLocation = location;
-                if (getIdentity().getPid() == Process.myPid() && location != null) {
-                    deliveryLocation = new Location(location);
+            return new ListenerOperation<LocationTransport>() {
+                @Override
+                public void operate(LocationTransport listener) throws Exception {
+                    // if delivering to the same process, make a copy of the location first (since
+                    // location is mutable)
+                    LocationResult deliverLocationResult;
+                    if (getIdentity().getPid() == Process.myPid() && locationResult != null) {
+                        deliverLocationResult = locationResult.deepCopy();
+                    } else {
+                        deliverLocationResult = locationResult;
+                    }
+
+                    // we currently don't hold a wakelock for getCurrentLocation deliveries
+                    listener.deliverOnLocationChanged(deliverLocationResult, null);
+                    mLocationEventLog.logProviderDeliveredLocations(mName,
+                            locationResult != null ? locationResult.size() : 0, getIdentity());
                 }
 
-                // we currently don't hold a wakelock for getCurrentLocation deliveries
-                listener.deliverOnLocationChanged(deliveryLocation, null);
-                mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
+                @Override
+                public void onPostExecute(boolean success) {
+                    // on failure we're automatically removed anyways, no need to attempt removal
+                    // again
+                    if (success) {
+                        synchronized (mLock) {
+                            remove();
+                        }
+                    }
+                }
+            };
+        }
 
+        @Override
+        public void onOperationFailure(ListenerOperation<LocationTransport> operation,
+                Exception e) {
+            if (e instanceof RemoteException) {
+                Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
                 synchronized (mLock) {
                     remove();
                 }
-            };
+            } else {
+                throw new AssertionError(e);
+            }
         }
 
         @Override
         public void binderDied() {
             try {
                 if (D) {
-                    Log.d(TAG, mName + " provider client died: " + getIdentity());
+                    Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
                 }
 
                 synchronized (mLock) {
@@ -1300,7 +1394,7 @@
         }
     }
 
-    public void setMockProvider(@Nullable MockProvider provider) {
+    public void setMockProvider(@Nullable MockLocationProvider provider) {
         synchronized (mLock) {
             Preconditions.checkState(mState != STATE_STOPPED);
 
@@ -1572,6 +1666,41 @@
         }
     }
 
+    public void flush(ILocationListener listener, int requestCode) {
+        synchronized (mLock) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                boolean flushed = updateRegistration(listener.asBinder(), registration -> {
+                    registration.flush(requestCode);
+                    return false;
+                });
+                if (!flushed) {
+                    throw new IllegalArgumentException("unregistered listener cannot be flushed");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    public void flush(PendingIntent pendingIntent, int requestCode) {
+        synchronized (mLock) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                boolean flushed = updateRegistration(pendingIntent, registration -> {
+                    registration.flush(requestCode);
+                    return false;
+                });
+                if (!flushed) {
+                    throw new IllegalArgumentException(
+                            "unregistered pending intent cannot be flushed");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
     public void unregisterLocationRequest(ILocationListener listener) {
         synchronized (mLock) {
             Preconditions.checkState(mState != STATE_STOPPED);
@@ -1820,19 +1949,22 @@
 
         long intervalMs = ProviderRequest.INTERVAL_DISABLED;
         int quality = LocationRequest.QUALITY_LOW_POWER;
+        long maxUpdateDelayMs = Long.MAX_VALUE;
         boolean locationSettingsIgnored = false;
         boolean lowPower = true;
 
         for (Registration registration : registrations) {
             LocationRequest request = registration.getRequest();
 
-            // passive requests do not contribute to the provider request
+            // passive requests do not contribute to the provider request, and passive requests
+            // must handle the batching parameters of non-passive requests
             if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
                 continue;
             }
 
             intervalMs = min(request.getIntervalMillis(), intervalMs);
             quality = min(request.getQuality(), quality);
+            maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
             locationSettingsIgnored |= request.isLocationSettingsIgnored();
             lowPower &= request.isLowPower();
         }
@@ -1841,6 +1973,11 @@
             return ProviderRequest.EMPTY_REQUEST;
         }
 
+        if (maxUpdateDelayMs / 2 < intervalMs) {
+            // reduces churn if only the batching parameter has changed
+            maxUpdateDelayMs = 0;
+        }
+
         // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
         // interval slightly higher that the minimum interval, and spread the blame across all
         // contributing registrations under that threshold (since worksource does not allow us to
@@ -1864,6 +2001,7 @@
         return new ProviderRequest.Builder()
                 .setIntervalMillis(intervalMs)
                 .setQuality(quality)
+                .setMaxUpdateDelayMillis(maxUpdateDelayMs)
                 .setLocationSettingsIgnored(locationSettingsIgnored)
                 .setLowPower(lowPower)
                 .setWorkSource(workSource)
@@ -2026,54 +2164,55 @@
 
     @GuardedBy("mLock")
     @Override
-    public void onReportLocation(Location location) {
+    public void onReportLocation(LocationResult locationResult) {
         if (Build.IS_DEBUGGABLE) {
             Preconditions.checkState(Thread.holdsLock(mLock));
         }
 
-        // don't validate mock locations
-        if (!location.isFromMockProvider()) {
-            if (location.getLatitude() == 0 && location.getLongitude() == 0) {
-                Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+        LocationResult filtered;
+        if (mPassiveManager != null) {
+            filtered = locationResult.filter(location -> {
+                if (!location.isFromMockProvider()) {
+                    if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+                        Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+                        return false;
+                    }
+                }
+
+                if (!location.isComplete()) {
+                    Log.w(TAG, "blocking incomplete location from " + mName + " provider");
+                    return false;
+                }
+
+                return true;
+            });
+
+            if (filtered == null) {
                 return;
             }
-        }
 
-        if (!location.isComplete()) {
-            Log.w(TAG, "blocking incomplete location from " + mName + " provider");
-            return;
-        }
-
-        if (mPassiveManager != null) {
             // don't log location received for passive provider because it's spammy
-            mLocationEventLog.logProviderReceivedLocation(mName);
+            mLocationEventLog.logProviderReceivedLocations(mName, filtered.size());
+        } else {
+            // passive provider should get already filtered results as input
+            filtered = locationResult;
         }
 
         // update last location
-        setLastLocation(location, UserHandle.USER_ALL);
+        setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL);
 
         // attempt listener delivery
         deliverToListeners(registration -> {
-            return registration.acceptLocationChange(location);
+            return registration.acceptLocationChange(filtered);
         });
 
         // notify passive provider
         if (mPassiveManager != null) {
-            mPassiveManager.updateLocation(location);
+            mPassiveManager.updateLocation(filtered);
         }
     }
 
     @GuardedBy("mLock")
-    @Override
-    public void onReportLocation(List<Location> locations) {
-        if (!GPS_PROVIDER.equals(mName)) {
-            return;
-        }
-
-        mLocationManagerInternal.reportGnssBatchLocations(locations);
-    }
-
-    @GuardedBy("mLock")
     private void onUserStarted(int userId) {
         if (Build.IS_DEBUGGABLE) {
             Preconditions.checkState(Thread.holdsLock(mLock));
@@ -2206,6 +2345,20 @@
         }
     }
 
+    private @Nullable LocationResult getPermittedLocationResult(
+            @Nullable LocationResult fineLocationResult, @PermissionLevel int permissionLevel) {
+        switch (permissionLevel) {
+            case PERMISSION_FINE:
+                return fineLocationResult;
+            case PERMISSION_COARSE:
+                return fineLocationResult != null ? mLocationFudger.createCoarse(fineLocationResult)
+                        : null;
+            default:
+                // shouldn't be possible to have a client added without location permissions
+                throw new AssertionError();
+        }
+    }
+
     public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
         synchronized (mLock) {
             ipw.print(mName);
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockLocationProvider.java
similarity index 85%
rename from services/core/java/com/android/server/location/MockProvider.java
rename to services/core/java/com/android/server/location/MockLocationProvider.java
index fc88f14..505a858 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockLocationProvider.java
@@ -20,6 +20,7 @@
 
 import android.annotation.Nullable;
 import android.location.Location;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Bundle;
 
@@ -34,11 +35,11 @@
  *
  * {@hide}
  */
-public class MockProvider extends AbstractLocationProvider {
+public class MockLocationProvider extends AbstractLocationProvider {
 
     @Nullable private Location mLocation;
 
-    public MockProvider(ProviderProperties properties, CallerIdentity identity) {
+    public MockLocationProvider(ProviderProperties properties, CallerIdentity identity) {
         // using a direct executor is ok because this class has no locks that could deadlock
         super(DIRECT_EXECUTOR, identity);
         setProperties(properties);
@@ -54,13 +55,18 @@
         Location location = new Location(l);
         location.setIsFromMockProvider(true);
         mLocation = location;
-        reportLocation(location);
+        reportLocation(LocationResult.wrap(location));
     }
 
     @Override
     public void onSetRequest(ProviderRequest request) {}
 
     @Override
+    protected void onFlush(Runnable callback) {
+        callback.run();
+    }
+
+    @Override
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index d8d435a..fa5339e 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -20,6 +20,7 @@
 
 import android.annotation.Nullable;
 import android.location.Location;
+import android.location.LocationResult;
 import android.os.Bundle;
 
 import com.android.internal.annotations.GuardedBy;
@@ -28,7 +29,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.List;
 
 /**
  * Represents a location provider that may switch between a mock implementation and a real
@@ -54,7 +54,7 @@
     @GuardedBy("mOwnerLock")
     @Nullable private AbstractLocationProvider mRealProvider;
     @GuardedBy("mOwnerLock")
-    @Nullable private MockProvider mMockProvider;
+    @Nullable private MockLocationProvider mMockProvider;
 
     @GuardedBy("mOwnerLock")
     private ProviderRequest mRequest;
@@ -113,7 +113,7 @@
      * inline invocation of {@link Listener#onStateChanged(State, State)} if this results in a
      * state change.
      */
-    public void setMockProvider(@Nullable MockProvider provider) {
+    public void setMockProvider(@Nullable MockLocationProvider provider) {
         synchronized (mOwnerLock) {
             if (mMockProvider == provider) {
                 return;
@@ -215,6 +215,17 @@
     }
 
     @Override
+    protected void onFlush(Runnable callback) {
+        synchronized (mOwnerLock) {
+            if (mProvider != null) {
+                mProvider.flush(callback);
+            } else {
+                callback.run();
+            }
+        }
+    }
+
+    @Override
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
         synchronized (mOwnerLock) {
             if (mProvider != null) {
@@ -272,24 +283,13 @@
         }
 
         @Override
-        public final void onReportLocation(Location location) {
+        public final void onReportLocation(LocationResult locationResult) {
             synchronized (mOwnerLock) {
                 if (mListenerProvider != mProvider) {
                     return;
                 }
 
-                reportLocation(location);
-            }
-        }
-
-        @Override
-        public final void onReportLocation(List<Location> locations) {
-            synchronized (mOwnerLock) {
-                if (mListenerProvider != mProvider) {
-                    return;
-                }
-
-                reportLocation(locations);
+                reportLocation(locationResult);
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveLocationProvider.java
similarity index 86%
rename from services/core/java/com/android/server/location/PassiveProvider.java
rename to services/core/java/com/android/server/location/PassiveLocationProvider.java
index f6896b8..ddae4ed 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProvider.java
@@ -20,7 +20,7 @@
 
 import android.content.Context;
 import android.location.Criteria;
-import android.location.Location;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Bundle;
 
@@ -37,7 +37,7 @@
  *
  * {@hide}
  */
-public class PassiveProvider extends AbstractLocationProvider {
+public class PassiveLocationProvider extends AbstractLocationProvider {
 
     private static final ProviderProperties PROPERTIES = new ProviderProperties(
             /* requiresNetwork = */false,
@@ -50,7 +50,7 @@
             Criteria.POWER_LOW,
             Criteria.ACCURACY_COARSE);
 
-    public PassiveProvider(Context context) {
+    public PassiveLocationProvider(Context context) {
         // using a direct executor is ok because this class has no locks that could deadlock
         super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context));
 
@@ -61,14 +61,19 @@
     /**
      * Pass a location into the passive provider.
      */
-    public void updateLocation(Location location) {
-        reportLocation(location);
+    public void updateLocation(LocationResult locationResult) {
+        reportLocation(locationResult);
     }
 
     @Override
     public void onSetRequest(ProviderRequest request) {}
 
     @Override
+    protected void onFlush(Runnable callback) {
+        callback.run();
+    }
+
+    @Override
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index b771861..343379a 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -18,8 +18,8 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
-import android.location.Location;
 import android.location.LocationManager;
+import android.location.LocationResult;
 import android.os.Binder;
 
 import com.android.internal.location.ProviderRequest;
@@ -36,25 +36,25 @@
 
     @Override
     public void setRealProvider(AbstractLocationProvider provider) {
-        Preconditions.checkArgument(provider instanceof PassiveProvider);
+        Preconditions.checkArgument(provider instanceof PassiveLocationProvider);
         super.setRealProvider(provider);
     }
 
     @Override
-    public void setMockProvider(@Nullable MockProvider provider) {
+    public void setMockProvider(@Nullable MockLocationProvider provider) {
         if (provider != null) {
             throw new IllegalArgumentException("Cannot mock the passive provider");
         }
     }
 
-    public void updateLocation(Location location) {
+    public void updateLocation(LocationResult locationResult) {
         synchronized (mLock) {
-            PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
-            Preconditions.checkState(passiveProvider != null);
+            PassiveLocationProvider passive = (PassiveLocationProvider) mProvider.getProvider();
+            Preconditions.checkState(passive != null);
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                passiveProvider.updateLocation(location);
+                passive.updateLocation(locationResult);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/ProxyLocationProvider.java
similarity index 71%
rename from services/core/java/com/android/server/location/LocationProviderProxy.java
rename to services/core/java/com/android/server/location/ProxyLocationProvider.java
index b111c15..ce9b10d 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/ProxyLocationProvider.java
@@ -21,7 +21,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
-import android.location.Location;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Binder;
 import android.os.Bundle;
@@ -38,21 +38,22 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Objects;
 
 /**
  * Proxy for ILocationProvider implementations.
  */
-public class LocationProviderProxy extends AbstractLocationProvider {
+public class ProxyLocationProvider extends AbstractLocationProvider {
 
     /**
      * Creates and registers this proxy. If no suitable service is available for the proxy, returns
      * null.
      */
     @Nullable
-    public static LocationProviderProxy createAndRegister(Context context, String action,
+    public static ProxyLocationProvider createAndRegister(Context context, String action,
             int enableOverlayResId, int nonOverlayPackageResId) {
-        LocationProviderProxy proxy = new LocationProviderProxy(context, action, enableOverlayResId,
+        ProxyLocationProvider proxy = new ProxyLocationProvider(context, action, enableOverlayResId,
                 nonOverlayPackageResId);
         if (proxy.register()) {
             return proxy;
@@ -67,13 +68,16 @@
     final ServiceWatcher mServiceWatcher;
 
     @GuardedBy("mLock")
+    final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
+
+    @GuardedBy("mLock")
     Proxy mProxy;
     @GuardedBy("mLock")
     @Nullable ComponentName mService;
 
     private volatile ProviderRequest mRequest;
 
-    private LocationProviderProxy(Context context, String action, int enableOverlayResId,
+    private ProxyLocationProvider(Context context, String action, int enableOverlayResId,
             int nonOverlayPackageResId) {
         // safe to use direct executor since our locks are not acquired in a code path invoked by
         // our owning provider
@@ -107,10 +111,18 @@
     }
 
     private void onUnbind() {
+        Runnable[] flushListeners;
         synchronized (mLock) {
             mProxy = null;
             mService = null;
             setState(State.EMPTY_STATE);
+            flushListeners = mFlushListeners.toArray(new Runnable[0]);
+            mFlushListeners.clear();
+        }
+
+        final int size = flushListeners.length;
+        for (int i = 0; i < size; ++i) {
+            flushListeners[i].run();
         }
     }
 
@@ -124,6 +136,38 @@
     }
 
     @Override
+    protected void onFlush(Runnable callback) {
+        mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+            @Override
+            public void run(IBinder binder) throws RemoteException {
+                ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+
+                // at first glance it would be more straightforward to pass the flush callback
+                // through to the provider and allow it to be invoked directly. however, in this
+                // case the binder calls 1) provider delivering flushed locations 2) provider
+                // delivering flush complete, while correctly ordered within the provider, would
+                // be invoked on different binder objects and thus would have no defined order
+                // on the system server side. thus, we ensure that both (1) and (2) are invoked
+                // on the same binder object (the ILocationProviderManager) and have a well
+                // defined ordering, so that the flush callback will always happen after
+                // location delivery.
+                synchronized (mLock) {
+                    mFlushListeners.add(callback);
+                }
+                provider.flush();
+            }
+
+            @Override
+            public void onError() {
+                synchronized (mLock) {
+                    mFlushListeners.remove(callback);
+                }
+                callback.run();
+            }
+        });
+    }
+
+    @Override
     public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
         mServiceWatcher.runOnBinder(binder -> {
             ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
@@ -209,12 +253,31 @@
 
         // executed on binder thread
         @Override
-        public void onReportLocation(Location location) {
+        public void onReportLocation(LocationResult locationResult) {
             synchronized (mLock) {
                 if (mProxy != this) {
                     return;
                 }
-                reportLocation(location);
+
+                reportLocation(locationResult.validate());
+            }
+        }
+
+        // executed on binder thread
+        @Override
+        public void onFlushComplete() {
+            Runnable callback = null;
+            synchronized (mLock) {
+                if (mProxy != this) {
+                    return;
+                }
+                if (!mFlushListeners.isEmpty()) {
+                    callback = mFlushListeners.remove(0);
+                }
+            }
+
+            if (callback != null) {
+                callback.run();
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
similarity index 91%
rename from services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java
rename to services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
index 6910c35..0427007 100644
--- a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java
+++ b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import java.util.concurrent.ConcurrentLinkedDeque;
 
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
similarity index 98%
rename from services/core/java/com/android/server/location/ContextHubClientBroker.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index e27eb65..20458b4 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
@@ -37,6 +37,8 @@
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.location.ClientBrokerProto;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
 
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
similarity index 98%
rename from services/core/java/com/android/server/location/ContextHubClientManager.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index 33ceeef..eda89ab 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.annotation.IntDef;
 import android.app.PendingIntent;
@@ -29,6 +29,8 @@
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.location.ClientManagerProto;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.DateFormat;
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
similarity index 99%
rename from services/core/java/com/android/server/location/ContextHubService.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 7a2e4ed..63a42f8 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -54,6 +54,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.DumpUtils;
+import com.android.server.location.ContextHubServiceProto;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java
similarity index 97%
rename from services/core/java/com/android/server/location/ContextHubServiceTransaction.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java
index 62bd91b..a31aecb 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.hardware.location.ContextHubTransaction;
 import android.hardware.location.NanoAppState;
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
similarity index 98%
rename from services/core/java/com/android/server/location/ContextHubServiceUtil.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 9145eca..88ed105 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
similarity index 99%
rename from services/core/java/com/android/server/location/ContextHubTransactionManager.java
rename to services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index d3fc705..f81208f 100644
--- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.hardware.contexthub.V1_0.IContexthub;
 import android.hardware.contexthub.V1_0.Result;
diff --git a/services/core/java/com/android/server/location/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
similarity index 99%
rename from services/core/java/com/android/server/location/IContextHubWrapper.java
rename to services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 9ac7c6b..4242d72 100644
--- a/services/core/java/com/android/server/location/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.annotation.Nullable;
 import android.hardware.contexthub.V1_1.Setting;
diff --git a/services/core/java/com/android/server/location/NanoAppStateManager.java b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
similarity index 98%
rename from services/core/java/com/android/server/location/NanoAppStateManager.java
rename to services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
index e26ccc3..60109fe 100644
--- a/services/core/java/com/android/server/location/NanoAppStateManager.java
+++ b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.contexthub;
 
 import android.annotation.Nullable;
 import android.hardware.contexthub.V1_0.HubAppInfo;
diff --git a/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
similarity index 98%
rename from services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
rename to services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
index 6117a9b..af3907e 100644
--- a/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.content.Context;
 import android.location.Country;
diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java
similarity index 93%
rename from services/core/java/com/android/server/location/CountryDetectorBase.java
rename to services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java
index 682b104..6e2e28c 100644
--- a/services/core/java/com/android/server/location/CountryDetectorBase.java
+++ b/services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.content.Context;
 import android.location.Country;
diff --git a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java
similarity index 98%
rename from services/core/java/com/android/server/location/LocationBasedCountryDetector.java
rename to services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java
index 8ee1285..638f36f 100644
--- a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.content.Context;
 import android.location.Address;
diff --git a/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java b/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java
deleted file mode 100644
index 057b178..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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.location.gnss;
-
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Manages GNSS Batching operations.
- *
- * <p>This class is not thread safe (It's client's responsibility to make sure calls happen on
- * the same thread).
- */
-public class GnssBatchingProvider {
-
-    private static final String TAG = "GnssBatchingProvider";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private final GnssBatchingProviderNative mNative;
-    private boolean mEnabled;
-    private boolean mStarted;
-    private long mPeriodNanos;
-    private boolean mWakeOnFifoFull;
-
-    GnssBatchingProvider() {
-        this(new GnssBatchingProviderNative());
-    }
-
-    @VisibleForTesting
-    GnssBatchingProvider(GnssBatchingProviderNative gnssBatchingProviderNative) {
-        mNative = gnssBatchingProviderNative;
-    }
-
-    /**
-     * Returns the GNSS batching size
-     */
-    public int getBatchSize() {
-        return mNative.getBatchSize();
-    }
-
-    /** Enable GNSS batching. */
-    public void enable() {
-        mEnabled = mNative.initBatching();
-        if (!mEnabled) {
-            Log.e(TAG, "Failed to initialize GNSS batching");
-        }
-    }
-
-    /**
-     * Starts the hardware batching operation
-     */
-    public boolean start(long periodNanos, boolean wakeOnFifoFull) {
-        if (!mEnabled) {
-            throw new IllegalStateException();
-        }
-        if (periodNanos <= 0) {
-            Log.e(TAG, "Invalid periodNanos " + periodNanos
-                    + " in batching request, not started");
-            return false;
-        }
-        mStarted = mNative.startBatch(periodNanos, wakeOnFifoFull);
-        if (mStarted) {
-            mPeriodNanos = periodNanos;
-            mWakeOnFifoFull = wakeOnFifoFull;
-        }
-        return mStarted;
-    }
-
-    /**
-     * Forces a flush of existing locations from the hardware batching
-     */
-    public void flush() {
-        if (!mStarted) {
-            Log.w(TAG, "Cannot flush since GNSS batching has not started.");
-            return;
-        }
-        mNative.flushBatch();
-    }
-
-    /**
-     * Stops the batching operation
-     */
-    public boolean stop() {
-        boolean stopped = mNative.stopBatch();
-        if (stopped) {
-            mStarted = false;
-        }
-        return stopped;
-    }
-
-    /** Disable GNSS batching. */
-    public void disable() {
-        stop();
-        mNative.cleanupBatching();
-        mEnabled = false;
-    }
-
-    // TODO(b/37460011): Use this with death recovery logic.
-    void resumeIfStarted() {
-        if (DEBUG) {
-            Log.d(TAG, "resumeIfStarted");
-        }
-        if (mStarted) {
-            mNative.startBatch(mPeriodNanos, mWakeOnFifoFull);
-        }
-    }
-
-    @VisibleForTesting
-    static class GnssBatchingProviderNative {
-        public int getBatchSize() {
-            return native_get_batch_size();
-        }
-
-        public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
-            return native_start_batch(periodNanos, wakeOnFifoFull);
-        }
-
-        public void flushBatch() {
-            native_flush_batch();
-        }
-
-        public boolean stopBatch() {
-            return native_stop_batch();
-        }
-
-        public boolean initBatching() {
-            return native_init_batching();
-        }
-
-        public void cleanupBatching() {
-            native_cleanup_batching();
-        }
-    }
-
-    private static native int native_get_batch_size();
-
-    private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
-
-    private static native void native_flush_batch();
-
-    private static native boolean native_stop_batch();
-
-    private static native boolean native_init_batching();
-
-    private static native void native_cleanup_batching();
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
index b8aa577..1c4fb10 100644
--- a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
@@ -29,7 +29,7 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final long GNSS_CAPABILITIES_TOP_HAL =
-            GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLACKLIST
+            GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLOCKLIST
                     | GnssCapabilities.GEOFENCING | GnssCapabilities.MEASUREMENTS
                     | GnssCapabilities.NAV_MESSAGES;
 
@@ -65,8 +65,8 @@
             gnssCapabilities |= GnssCapabilities.LOW_POWER_MODE;
         }
         if (hasCapability(topHalCapabilities,
-                GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLACKLIST)) {
-            gnssCapabilities |= GnssCapabilities.SATELLITE_BLACKLIST;
+                GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLOCKLIST)) {
+            gnssCapabilities |= GnssCapabilities.SATELLITE_BLOCKLIST;
         }
         if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_GEOFENCING)) {
             gnssCapabilities |= GnssCapabilities.GEOFENCING;
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 890f51b..2628372 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -71,6 +71,11 @@
     private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
     private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
     public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
+    private static final String CONFIG_LONGTERM_PSDS_SERVER_1 = "LONGTERM_PSDS_SERVER_1";
+    private static final String CONFIG_LONGTERM_PSDS_SERVER_2 = "LONGTERM_PSDS_SERVER_2";
+    private static final String CONFIG_LONGTERM_PSDS_SERVER_3 = "LONGTERM_PSDS_SERVER_3";
+    private static final String CONFIG_NORMAL_PSDS_SERVER = "NORMAL_PSDS_SERVER";
+    private static final String CONFIG_REALTIME_PSDS_SERVER = "REALTIME_PSDS_SERVER";
 
     // Limit on NI emergency mode time extension after emergency sessions ends
     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
@@ -202,8 +207,8 @@
     /**
      * Updates the GNSS HAL satellite denylist.
      */
-    void setSatelliteBlacklist(int[] constellations, int[] svids) {
-        native_set_satellite_blacklist(constellations, svids);
+    void setSatelliteBlocklist(int[] constellations, int[] svids) {
+        native_set_satellite_blocklist(constellations, svids);
     }
 
     HalInterfaceVersion getHalInterfaceVersion() {
@@ -227,11 +232,14 @@
             // override default value of this if lpp_prof is not empty
             mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
         }
+
+        // Load Psds servers from resources
+        loadPsdsServersFromResources();
+
         /*
          * Overlay carrier properties from a debug configuration file.
          */
         loadPropertiesFromGpsDebugConfig(mProperties);
-
         mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
 
         logConfigurations();
@@ -380,6 +388,34 @@
         }
     }
 
+    void loadPsdsServersFromResources() {
+        String longTermPsdsServer1 = mContext.getResources().getString(
+                com.android.internal.R.string.config_longterm_psds_server_1);
+        if (!TextUtils.isEmpty(longTermPsdsServer1)) {
+            mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_1, longTermPsdsServer1);
+        }
+        String longTermPsdsServer2 = mContext.getResources().getString(
+                com.android.internal.R.string.config_longterm_psds_server_2);
+        if (!TextUtils.isEmpty(longTermPsdsServer2)) {
+            mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_2, longTermPsdsServer2);
+        }
+        String longTermPsdsServer3 = mContext.getResources().getString(
+                com.android.internal.R.string.config_longterm_psds_server_3);
+        if (!TextUtils.isEmpty(longTermPsdsServer3)) {
+            mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_3, longTermPsdsServer3);
+        }
+        String normalPsdsServer = mContext.getResources().getString(
+                com.android.internal.R.string.config_normal_psds_server);
+        if (!TextUtils.isEmpty(normalPsdsServer)) {
+            mProperties.setProperty(CONFIG_NORMAL_PSDS_SERVER, normalPsdsServer);
+        }
+        String realtimePsdsServer = mContext.getResources().getString(
+                com.android.internal.R.string.config_realtime_psds_server);
+        if (!TextUtils.isEmpty(realtimePsdsServer)) {
+            mProperties.setProperty(CONFIG_REALTIME_PSDS_SERVER, realtimePsdsServer);
+        }
+    }
+
     private static boolean isConfigEsExtensionSecSupported(
             HalInterfaceVersion gnssConfiguartionIfaceVersion) {
         // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
@@ -414,7 +450,7 @@
 
     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
 
-    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+    private static native boolean native_set_satellite_blocklist(int[] constellations, int[] svIds);
 
     private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
 }
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 0c1e91d..55073c0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.server.location.gnss;
 
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -39,6 +41,7 @@
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationRequest;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.AsyncTask;
 import android.os.BatteryStats;
@@ -78,7 +81,7 @@
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.location.AbstractLocationProvider;
-import com.android.server.location.gnss.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
+import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback;
 import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
 import com.android.server.location.util.Injector;
 
@@ -97,7 +100,7 @@
  */
 public class GnssLocationProvider extends AbstractLocationProvider implements
         InjectNtpTimeCallback,
-        GnssSatelliteBlacklistCallback {
+        GnssSatelliteBlocklistCallback {
 
     private static final String TAG = "GnssLocationProvider";
 
@@ -171,7 +174,7 @@
     public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
     public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
     public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
-    public static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
+    public static final int GPS_CAPABILITY_SATELLITE_BLOCKLIST = 0x0000200;
     public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400;
     public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800;
 
@@ -298,6 +301,9 @@
     @GuardedBy("mLock")
     private boolean mGpsEnabled;
 
+    @GuardedBy("mLock")
+    private boolean mBatchingEnabled;
+
     private boolean mShutdown;
 
     @GuardedBy("mLock")
@@ -315,6 +321,9 @@
     // true if we started navigation in the HAL, only change value of this in setStarted
     private boolean mStarted;
 
+    // true if batching is being used
+    private boolean mBatchingStarted;
+
     // for logging of latest change, and warning of ongoing location after a stop
     private long mStartedChangedElapsedRealtime;
 
@@ -371,10 +380,9 @@
     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
     private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
     private final NtpTimeHelper mNtpTimeHelper;
-    private final GnssBatchingProvider mGnssBatchingProvider;
     private final GnssGeofenceProvider mGnssGeofenceProvider;
     private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
-    private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
+    private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper;
 
     // Available only on GNSS HAL 2.0 implementations and later.
     private GnssVisibilityControl mGnssVisibilityControl;
@@ -421,6 +429,9 @@
 
     private volatile boolean mItarSpeedLimitExceeded = false;
 
+    @GuardedBy("mLock")
+    private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
+
     // GNSS Metrics
     private GnssMetrics mGnssMetrics;
 
@@ -494,11 +505,11 @@
     };
 
     /**
-     * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
+     * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}.
      */
     @Override
-    public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
-        mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids));
+    public void onUpdateSatelliteBlocklist(int[] constellations, int[] svids) {
+        mHandler.post(() -> mGnssConfiguration.setSatelliteBlocklist(constellations, svids));
         mGnssMetrics.resetConstellationTypes();
     }
 
@@ -622,10 +633,9 @@
 
         mGnssMetrics = new GnssMetrics(mContext, mBatteryStats);
         mNtpTimeHelper = new NtpTimeHelper(mContext, mLooper, this);
-        mGnssSatelliteBlacklistHelper =
-                new GnssSatelliteBlacklistHelper(mContext,
+        mGnssSatelliteBlocklistHelper =
+                new GnssSatelliteBlocklistHelper(mContext,
                         mLooper, this);
-        mGnssBatchingProvider = new GnssBatchingProvider();
         mGnssGeofenceProvider = new GnssGeofenceProvider();
 
         setProperties(PROPERTIES);
@@ -655,7 +665,7 @@
                 }, UserHandle.USER_ALL);
 
         sendMessage(INITIALIZE_HANDLER, 0, null);
-        mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
+        mHandler.post(mGnssSatelliteBlocklistHelper::updateSatelliteBlocklist);
     }
 
     /**
@@ -922,7 +932,7 @@
                         mC2KServerHost, mC2KServerPort);
             }
 
-            mGnssBatchingProvider.enable();
+            mBatchingEnabled = native_init_batching() && native_get_batch_size() > 1;
             if (mGnssVisibilityControl != null) {
                 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true);
             }
@@ -938,13 +948,11 @@
         setGpsEnabled(false);
         updateClientUids(new WorkSource());
         stopNavigating();
-        mAlarmManager.cancel(mWakeupIntent);
-        mAlarmManager.cancel(mTimeoutIntent);
+        stopBatching();
 
         if (mGnssVisibilityControl != null) {
             mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false);
         }
-        mGnssBatchingProvider.disable();
         // do this before releasing wakelock
         native_cleanup();
     }
@@ -957,7 +965,7 @@
         // ... but disable if PowerManager overrides
         enabled &= !mDisableGpsForPowerManager;
 
-        // .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
+        // .. but enable anyway, if there's an active settings-ignored request
         enabled |= (mProviderRequest != null
                 && mProviderRequest.isActive()
                 && mProviderRequest.isLocationSettingsIgnored());
@@ -982,6 +990,30 @@
         }
     }
 
+    /**
+     * Returns the hardware batch size available in this hardware implementation. If the available
+     * size is variable, for example, based on other operations consuming memory, this is the
+     * minimum size guaranteed to be available for batching operations.
+     */
+    public int getBatchSize() {
+        return native_get_batch_size();
+    }
+
+    @Override
+    protected void onFlush(Runnable listener) {
+        boolean added = false;
+        synchronized (mLock) {
+            if (mBatchingEnabled) {
+                added = mFlushListeners.add(listener);
+            }
+        }
+        if (!added) {
+            listener.run();
+        } else {
+            native_flush_batch();
+        }
+    }
+
     @Override
     public void onSetRequest(ProviderRequest request) {
         sendMessage(SET_REQUEST, 0, request);
@@ -1011,46 +1043,64 @@
                 Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis());
                 mFixInterval = Integer.MAX_VALUE;
             }
+            // requested batch size, or zero to disable batching
+            int batchSize;
+            try {
+                batchSize = mBatchingEnabled ? Math.toIntExact(
+                        mProviderRequest.getMaxUpdateDelayMillis() / mFixInterval) : 0;
+            } catch (ArithmeticException e) {
+                batchSize = Integer.MAX_VALUE;
+            }
+
+            if (batchSize < getBatchSize()) {
+                batchSize = 0;
+            }
 
             // apply request to GPS engine
-            if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
-                // change period and/or lowPowerMode
-                if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                        mFixInterval, 0, 0, mLowPowerMode)) {
-                    Log.e(TAG, "set_position_mode failed in updateRequirements");
-                }
-            } else if (!mStarted) {
-                // start GPS
-                startNavigating();
+            if (batchSize > 0) {
+                stopNavigating();
+                startBatching();
             } else {
-                // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
-                mAlarmManager.cancel(mTimeoutIntent);
-                if (mFixInterval >= NO_FIX_TIMEOUT) {
-                    // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
-                    // and our fix interval is not short
-                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                            SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+                stopBatching();
+
+                if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+                    // change period and/or lowPowerMode
+                    if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+                            mFixInterval, mLowPowerMode)) {
+                        Log.e(TAG, "set_position_mode failed in updateRequirements");
+                    }
+                } else if (!mStarted) {
+                    // start GPS
+                    startNavigating();
+                } else {
+                    // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
+                    mAlarmManager.cancel(mTimeoutIntent);
+                    if (mFixInterval >= NO_FIX_TIMEOUT) {
+                        // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
+                        // and our fix interval is not short
+                        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                                SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+                    }
                 }
             }
         } else {
             updateClientUids(new WorkSource());
 
             stopNavigating();
-            mAlarmManager.cancel(mWakeupIntent);
-            mAlarmManager.cancel(mTimeoutIntent);
+            stopBatching();
         }
     }
 
     private boolean setPositionMode(int mode, int recurrence, int minInterval,
-            int preferredAccuracy, int preferredTime, boolean lowPowerMode) {
+            boolean lowPowerMode) {
         GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval,
-                preferredAccuracy, preferredTime, lowPowerMode);
+                0, 0, lowPowerMode);
         if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) {
             return true;
         }
 
         boolean result = native_set_position_mode(mode, recurrence, minInterval,
-                preferredAccuracy, preferredTime, lowPowerMode);
+                0, 0, lowPowerMode);
         if (result) {
             mLastPositionMode = positionMode;
         } else {
@@ -1210,7 +1260,7 @@
             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
             mLowPowerMode = mProviderRequest.isLowPower();
             if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
-                    interval, 0, 0, mLowPowerMode)) {
+                    interval, mLowPowerMode)) {
                 setStarted(false);
                 Log.e(TAG, "set_position_mode failed in startNavigating()");
                 return;
@@ -1247,6 +1297,27 @@
             // reset SV count to zero
             mLocationExtras.reset();
         }
+        mAlarmManager.cancel(mTimeoutIntent);
+        mAlarmManager.cancel(mWakeupIntent);
+    }
+
+    private void startBatching() {
+        if (DEBUG) {
+            Log.d(TAG, "startBatching " + mFixInterval);
+        }
+        if (native_start_batch(MILLISECONDS.toNanos(mFixInterval), true)) {
+            mBatchingStarted = true;
+        } else {
+            Log.e(TAG, "native_start_batch failed in startBatching()");
+        }
+    }
+
+    private void stopBatching() {
+        if (DEBUG) Log.d(TAG, "stopBatching");
+        if (mBatchingStarted) {
+            native_stop_batch();
+            mBatchingStarted = false;
+        }
     }
 
     private void setStarted(boolean started) {
@@ -1259,8 +1330,6 @@
     private void hibernate() {
         // stop GPS until our next fix interval arrives
         stopNavigating();
-        mAlarmManager.cancel(mTimeoutIntent);
-        mAlarmManager.cancel(mWakeupIntent);
         long now = SystemClock.elapsedRealtime();
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
     }
@@ -1291,7 +1360,7 @@
 
         location.setExtras(mLocationExtras.getBundle());
 
-        reportLocation(location);
+        reportLocation(LocationResult.wrap(location).validate());
 
         if (mStarted) {
             mGnssMetrics.logReceivedLocationStatus(hasLatLong);
@@ -1474,7 +1543,6 @@
         Log.i(TAG, "restartRequests");
 
         restartLocationRequest();
-        mGnssBatchingProvider.resumeIfStarted();
         mGnssGeofenceProvider.resumeIfStarted();
     }
 
@@ -1545,13 +1613,6 @@
     }
 
     /**
-     * @hide
-     */
-    public GnssBatchingProvider getGnssBatchingProvider() {
-        return mGnssBatchingProvider;
-    }
-
-    /**
      * Interface for GnssMetrics methods.
      */
     public interface GnssMetricsProvider {
@@ -1575,12 +1636,24 @@
         return mGnssCapabilitiesProvider;
     }
 
-    void reportLocationBatch(Location[] locationArray) {
-        List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
+    void reportLocationBatch(Location[] locations) {
         if (DEBUG) {
-            Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
+            Log.d(TAG, "Location batch of size " + locations.length + " reported");
         }
-        reportLocation(locations);
+
+        Runnable[] listeners;
+        synchronized (mLock) {
+            listeners = mFlushListeners.toArray(new Runnable[0]);
+            mFlushListeners.clear();
+        }
+
+        if (locations.length > 0) {
+            reportLocation(LocationResult.create(Arrays.asList(locations)).validate());
+        }
+
+        for (Runnable listener : listeners) {
+            listener.run();
+        }
     }
 
     void downloadPsdsData(int psdsType) {
@@ -2032,6 +2105,9 @@
         TimeUtils.formatDuration(SystemClock.elapsedRealtime()
                 - mStartedChangedElapsedRealtime, s);
         s.append(" ago)").append('\n');
+        s.append("mBatchingEnabled=").append(mBatchingEnabled).append('\n');
+        s.append("mBatchingStarted=").append(mBatchingStarted).append('\n');
+        s.append("mBatchSize=").append(getBatchSize()).append('\n');
         s.append("mFixInterval=").append(mFixInterval).append('\n');
         s.append("mLowPowerMode=").append(mLowPowerMode).append('\n');
         s.append("mDisableGpsForPowerManager=").append(mDisableGpsForPowerManager).append('\n');
@@ -2046,7 +2122,7 @@
         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
         if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
-        if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
+        if (hasCapability(GPS_CAPABILITY_SATELLITE_BLOCKLIST)) s.append("SATELLITE_BLOCKLIST ");
         if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
             s.append("MEASUREMENT_CORRECTIONS ");
         }
@@ -2067,7 +2143,7 @@
     }
 
     // preallocated to avoid memory allocation in reportNmea()
-    private byte[] mNmeaBuffer = new byte[120];
+    private final byte[] mNmeaBuffer = new byte[120];
 
     private static native boolean native_is_gnss_visibility_control_supported();
 
@@ -2119,4 +2195,16 @@
             int lac, int cid);
 
     private native void native_agps_set_id(int type, String setid);
+
+    private static native boolean native_init_batching();
+
+    private static native void native_cleanup_batching();
+
+    private static native int native_get_batch_size();
+
+    private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+
+    private static native void native_flush_batch();
+
+    private static native boolean native_stop_batch();
 }
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 2bf6af2..47c528b 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -16,18 +16,14 @@
 
 package com.android.server.location.gnss;
 
-import static android.location.LocationManager.GPS_PROVIDER;
-
 import android.Manifest;
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.content.Context;
 import android.location.GnssAntennaInfo;
 import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssNavigationMessage;
 import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
@@ -37,12 +33,10 @@
 import android.location.Location;
 import android.location.LocationManagerInternal;
 import android.location.util.identity.CallerIdentity;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
@@ -77,21 +71,9 @@
     private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
     private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
     private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
-    private final GnssBatchingProvider mGnssBatchingProvider;
     private final INetInitiatedListener mNetInitiatedListener;
     private final IGpsGeofenceHardware mGpsGeofenceProxy;
 
-    private final Object mGnssBatchingLock = new Object();
-
-    @GuardedBy("mGnssBatchingLock")
-    @Nullable private IBatchedLocationCallback mGnssBatchingCallback;
-    @GuardedBy("mGnssBatchingLock")
-    @Nullable private CallerIdentity mGnssBatchingIdentity;
-    @GuardedBy("mGnssBatchingLock")
-    @Nullable private Binder.DeathRecipient mGnssBatchingDeathRecipient;
-    @GuardedBy("mGnssBatchingLock")
-    private boolean mGnssBatchingInProgress = false;
-
     public GnssManagerService(Context context, Injector injector) {
         this(context, injector, null);
     }
@@ -121,7 +103,6 @@
         mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
         mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
         mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
-        mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
         mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
         mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
 
@@ -171,108 +152,7 @@
      * Get size of GNSS batch (GNSS location results are batched together for power savings).
      */
     public int getGnssBatchSize() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
-        synchronized (mGnssBatchingLock) {
-            return mGnssBatchingProvider.getBatchSize();
-        }
-    }
-
-    /**
-     * Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
-     * as a collection.
-     */
-    public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName,
-            String attributionTag) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-
-        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
-        if (!mAppOpsHelper.checkOpNoThrow(AppOpsManager.OP_FINE_LOCATION, identity)) {
-            return false;
-        }
-
-        synchronized (mGnssBatchingLock) {
-            if (mGnssBatchingInProgress) {
-                // Current design does not expect multiple starts to be called repeatedly
-                Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
-                stopGnssBatch();
-            }
-
-            mGnssBatchingInProgress = true;
-            return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
-        }
-    }
-
-    /**
-     * Adds a GNSS batching callback for delivering GNSS location batch results.
-     */
-    public boolean setGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
-            @Nullable String attributionTag) {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-
-        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
-
-        synchronized (mGnssBatchingLock) {
-            Binder.DeathRecipient deathRecipient = () -> {
-                synchronized (mGnssBatchingLock) {
-                    stopGnssBatch();
-                    removeGnssBatchingCallback();
-                }
-            };
-
-            try {
-                callback.asBinder().linkToDeath(mGnssBatchingDeathRecipient, 0);
-                mGnssBatchingCallback = callback;
-                mGnssBatchingIdentity = identity;
-                mGnssBatchingDeathRecipient = deathRecipient;
-                return true;
-            } catch (RemoteException e) {
-                return false;
-            }
-        }
-    }
-
-    /**
-     * Force flush GNSS location results from batch.
-     */
-    public void flushGnssBatch() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
-        synchronized (mGnssBatchingLock) {
-            mGnssBatchingProvider.flush();
-        }
-    }
-
-    /**
-     * Removes GNSS batching callback.
-     */
-    public void removeGnssBatchingCallback() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
-        synchronized (mGnssBatchingLock) {
-            if (mGnssBatchingCallback == null) {
-                return;
-            }
-
-            mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathRecipient, 0);
-            mGnssBatchingCallback = null;
-            mGnssBatchingIdentity = null;
-            mGnssBatchingDeathRecipient = null;
-        }
-    }
-
-    /**
-     * Stop GNSS batch collection.
-     */
-    public boolean stopGnssBatch() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
-        synchronized (mGnssBatchingLock) {
-            mGnssBatchingInProgress = false;
-            return mGnssBatchingProvider.stop();
-        }
+        return mGnssLocationProvider.getBatchSize();
     }
 
     /**
@@ -377,34 +257,6 @@
     }
 
     /**
-     * Report location results to GNSS batching listener.
-     */
-    public void onReportLocation(List<Location> locations) {
-        IBatchedLocationCallback callback;
-        CallerIdentity identity;
-        synchronized (mGnssBatchingLock) {
-            callback = mGnssBatchingCallback;
-            identity = mGnssBatchingIdentity;
-        }
-
-        if (callback == null || identity == null) {
-            return;
-        }
-
-        if (!mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER,
-                identity.getUserId())) {
-            Log.w(TAG, "reportLocationBatch() called without user permission");
-            return;
-        }
-
-        try {
-            callback.onLocationBatch(locations);
-        } catch (RemoteException e) {
-            // ignore
-        }
-    }
-
-    /**
      * Dump info for debugging.
      */
     public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
@@ -434,12 +286,6 @@
         ipw.increaseIndent();
         mGnssStatusProvider.dump(fd, ipw, args);
         ipw.decreaseIndent();
-
-        synchronized (mGnssBatchingLock) {
-            if (mGnssBatchingInProgress) {
-                ipw.println("GNSS batching in progress");
-            }
-        }
     }
 
     // all native callbacks - to be funneled to various locations as appropriate
diff --git a/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java
similarity index 61%
rename from services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java
rename to services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java
index 426ce8c..baee5bf 100644
--- a/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java
+++ b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java
@@ -33,72 +33,72 @@
 /**
  * Detects denylist change and updates the denylist.
  */
-class GnssSatelliteBlacklistHelper {
+class GnssSatelliteBlocklistHelper {
 
-    private static final String TAG = "GnssBlacklistHelper";
-    private static final String BLACKLIST_DELIMITER = ",";
+    private static final String TAG = "GnssBlocklistHelper";
+    private static final String BLOCKLIST_DELIMITER = ",";
 
     private final Context mContext;
-    private final GnssSatelliteBlacklistCallback mCallback;
+    private final GnssSatelliteBlocklistCallback mCallback;
 
-    interface GnssSatelliteBlacklistCallback {
-        void onUpdateSatelliteBlacklist(int[] constellations, int[] svids);
+    interface GnssSatelliteBlocklistCallback {
+        void onUpdateSatelliteBlocklist(int[] constellations, int[] svids);
     }
 
-    GnssSatelliteBlacklistHelper(Context context, Looper looper,
-            GnssSatelliteBlacklistCallback callback) {
+    GnssSatelliteBlocklistHelper(Context context, Looper looper,
+            GnssSatelliteBlocklistCallback callback) {
         mContext = context;
         mCallback = callback;
         ContentObserver contentObserver = new ContentObserver(new Handler(looper)) {
             @Override
             public void onChange(boolean selfChange) {
-                updateSatelliteBlacklist();
+                updateSatelliteBlocklist();
             }
         };
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(
-                        Settings.Global.GNSS_SATELLITE_BLACKLIST),
+                        Settings.Global.GNSS_SATELLITE_BLOCKLIST),
                 true,
                 contentObserver, UserHandle.USER_ALL);
     }
 
-    void updateSatelliteBlacklist() {
+    void updateSatelliteBlocklist() {
         ContentResolver resolver = mContext.getContentResolver();
-        String blacklist = Settings.Global.getString(
+        String blocklist = Settings.Global.getString(
                 resolver,
-                Settings.Global.GNSS_SATELLITE_BLACKLIST);
-        if (blacklist == null) {
-            blacklist = "";
+                Settings.Global.GNSS_SATELLITE_BLOCKLIST);
+        if (blocklist == null) {
+            blocklist = "";
         }
-        Log.i(TAG, String.format("Update GNSS satellite blacklist: %s", blacklist));
+        Log.i(TAG, String.format("Update GNSS satellite blocklist: %s", blocklist));
 
-        List<Integer> blacklistValues;
+        List<Integer> blocklistValues;
         try {
-            blacklistValues = parseSatelliteBlacklist(blacklist);
+            blocklistValues = parseSatelliteBlocklist(blocklist);
         } catch (NumberFormatException e) {
-            Log.e(TAG, "Exception thrown when parsing blacklist string.", e);
+            Log.e(TAG, "Exception thrown when parsing blocklist string.", e);
             return;
         }
 
-        if (blacklistValues.size() % 2 != 0) {
-            Log.e(TAG, "blacklist string has odd number of values."
-                    + "Aborting updateSatelliteBlacklist");
+        if (blocklistValues.size() % 2 != 0) {
+            Log.e(TAG, "blocklist string has odd number of values."
+                    + "Aborting updateSatelliteBlocklist");
             return;
         }
 
-        int length = blacklistValues.size() / 2;
+        int length = blocklistValues.size() / 2;
         int[] constellations = new int[length];
         int[] svids = new int[length];
         for (int i = 0; i < length; i++) {
-            constellations[i] = blacklistValues.get(i * 2);
-            svids[i] = blacklistValues.get(i * 2 + 1);
+            constellations[i] = blocklistValues.get(i * 2);
+            svids[i] = blocklistValues.get(i * 2 + 1);
         }
-        mCallback.onUpdateSatelliteBlacklist(constellations, svids);
+        mCallback.onUpdateSatelliteBlocklist(constellations, svids);
     }
 
     @VisibleForTesting
-    static List<Integer> parseSatelliteBlacklist(String blacklist) throws NumberFormatException {
-        String[] strings = blacklist.split(BLACKLIST_DELIMITER);
+    static List<Integer> parseSatelliteBlocklist(String blocklist) throws NumberFormatException {
+        String[] strings = blocklist.split(BLOCKLIST_DELIMITER);
         List<Integer> parsed = new ArrayList<>(strings.length);
         for (String string : strings) {
             string = string.trim();
diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
index d6b179b..709e236 100644
--- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
@@ -32,8 +32,7 @@
  * @param <TListener> listener type
  */
 public abstract class BinderListenerRegistration<TRequest, TListener> extends
-        RemoteListenerRegistration<TRequest, TListener> implements
-        Binder.DeathRecipient {
+        RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
 
     /**
      * Interface to allow binder retrieval when keys are not themselves IBinders.
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 6b93616..33b08d4 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -79,8 +79,7 @@
  * @param <TMergedRegistration> merged registration type
  */
 public abstract class ListenerMultiplexer<TKey, TListener,
-        TRegistration extends ListenerRegistration<TListener>,
-        TMergedRegistration> {
+        TRegistration extends ListenerRegistration<TListener>, TMergedRegistration> {
 
     @GuardedBy("mRegistrations")
     private final ArrayMap<TKey, TRegistration> mRegistrations = new ArrayMap<>();
@@ -484,6 +483,38 @@
         }
     }
 
+    /**
+     * Evaluates the predicate on a registration with the given key. The predicate should return
+     * true if the active state of the registration may have changed as a result. If the active
+     * state of the registration has changed, {@link #updateService()} will automatically be invoked
+     * to handle the resulting changes. Returns true if there is a registration with the given key
+     * (and thus the predicate was invoked), and false otherwise.
+     */
+    protected final boolean updateRegistration(@NonNull Object key,
+            @NonNull Predicate<TRegistration> predicate) {
+        synchronized (mRegistrations) {
+            // since updating a registration can invoke a variety of callbacks, we need to ensure
+            // those callbacks themselves do not re-enter, as this could lead to out-of-order
+            // callbacks. note that try-with-resources ordering is meaningful here as well. we want
+            // to close the reentrancy guard first, as this may generate additional service updates,
+            // then close the update service buffer.
+            try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
+                 ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
+
+                int index = mRegistrations.indexOfKey(key);
+                if (index < 0) {
+                    return false;
+                }
+
+                TRegistration registration = mRegistrations.valueAt(index);
+                if (predicate.test(registration)) {
+                    onRegistrationActiveChanged(registration);
+                }
+                return true;
+            }
+        }
+    }
+
     @GuardedBy("mRegistrations")
     private void onRegistrationActiveChanged(TRegistration registration) {
         if (Build.IS_DEBUGGABLE) {
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index fa21b3a..711dde8 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -16,7 +16,6 @@
 
 package com.android.server.location.listeners;
 
-
 import android.annotation.Nullable;
 
 import com.android.internal.listeners.ListenerExecutor;
@@ -108,8 +107,8 @@
      * May be overridden by subclasses to handle listener operation failures. The default behavior
      * is to further propagate any exceptions. Will always be invoked on the executor thread.
      */
-    protected void onOperationFailure(ListenerOperation<TListener> operation, Exception e) {
-        throw new AssertionError(e);
+    protected void onOperationFailure(ListenerOperation<TListener> operation, Exception exception) {
+        throw new AssertionError(exception);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index 43eb3ca..280d59af 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -211,6 +211,8 @@
      * {@link SimulatedLocationTimeZoneProviderProxy}. If not, the event is logged but discarded.
      */
     void simulateBinderProviderEvent(SimulatedBinderProviderEvent event) {
+        mThreadingDomain.assertCurrentThread();
+
         if (!(mProxy instanceof SimulatedLocationTimeZoneProviderProxy)) {
             Slog.w(TAG, mProxy + " is not a " + SimulatedLocationTimeZoneProviderProxy.class
                     + ", event=" + event);
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index 621828e..70c1aef 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -560,10 +560,12 @@
     }
 
     /**
-     * Asynchronously passes a {@link SimulatedBinderProviderEvent] to the appropriate provider.
+     * Passes a {@link SimulatedBinderProviderEvent] to the appropriate provider.
      * If the provider name does not match a known provider, then the event is logged and discarded.
      */
     void simulateBinderProviderEvent(@NonNull SimulatedBinderProviderEvent event) {
+        mThreadingDomain.assertCurrentThread();
+
         String targetProviderName = event.getProviderName();
         LocationTimeZoneProvider targetProvider;
         if (Objects.equals(mPrimaryProvider.getName(), targetProviderName)) {
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
index 462bcab..604ff74 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
@@ -37,10 +37,11 @@
  */
 class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
 
-    @GuardedBy("mProxyLock")
+    @GuardedBy("mSharedLock")
     @NonNull private LocationTimeZoneProviderRequest mRequest;
 
-    @NonNull private ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
+    @GuardedBy("mSharedLock")
+    @NonNull private final ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
 
     SimulatedLocationTimeZoneProviderProxy(
             @NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
@@ -49,29 +50,36 @@
     }
 
     void simulate(@NonNull SimulatedBinderProviderEvent event) {
-        switch (event.getEventType()) {
-            case INJECTED_EVENT_TYPE_ON_BIND: {
-                mLastEvent.set("Simulating onProviderBound(), event=" + event);
-                mThreadingDomain.post(this::onBindOnHandlerThread);
-                break;
-            }
-            case INJECTED_EVENT_TYPE_ON_UNBIND: {
-                mLastEvent.set("Simulating onProviderUnbound(), event=" + event);
-                mThreadingDomain.post(this::onUnbindOnHandlerThread);
-                break;
-            }
-            case INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT: {
-                if (!mRequest.getReportLocationTimeZone()) {
-                    mLastEvent.set("Test event=" + event + " is testing an invalid case:"
-                            + " reporting is off. mRequest=" + mRequest);
+        mThreadingDomain.assertCurrentThread();
+
+        Objects.requireNonNull(event);
+
+        synchronized (mSharedLock) {
+            switch (event.getEventType()) {
+                case INJECTED_EVENT_TYPE_ON_BIND: {
+                    mLastEvent.set("Simulating onProviderBound(), event=" + event);
+                    mThreadingDomain.post(this::onBindOnHandlerThread);
+                    break;
                 }
-                mLastEvent.set("Simulating LocationTimeZoneEvent, event=" + event);
-                handleLocationTimeZoneEvent(event.getLocationTimeZoneEvent());
-                break;
-            }
-            default: {
-                mLastEvent.set("Unknown simulated event type. event=" + event);
-                throw new IllegalArgumentException("Unknown simulated event type. event=" + event);
+                case INJECTED_EVENT_TYPE_ON_UNBIND: {
+                    mLastEvent.set("Simulating onProviderUnbound(), event=" + event);
+                    mThreadingDomain.post(this::onUnbindOnHandlerThread);
+                    break;
+                }
+                case INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT: {
+                    if (!mRequest.getReportLocationTimeZone()) {
+                        mLastEvent.set("Test event=" + event + " is testing an invalid case:"
+                                + " reporting is off. mRequest=" + mRequest);
+                    }
+                    mLastEvent.set("Simulating LocationTimeZoneEvent, event=" + event);
+                    handleLocationTimeZoneEvent(event.getLocationTimeZoneEvent());
+                    break;
+                }
+                default: {
+                    mLastEvent.set("Unknown simulated event type. event=" + event);
+                    throw new IllegalArgumentException(
+                            "Unknown simulated event type. event=" + event);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/util/LocationEventLog.java b/services/core/java/com/android/server/location/util/LocationEventLog.java
index e4c354b..ff4503e 100644
--- a/services/core/java/com/android/server/location/util/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/util/LocationEventLog.java
@@ -90,14 +90,14 @@
     }
 
     /** Logs a new incoming location for a location provider. */
-    public synchronized void logProviderReceivedLocation(String provider) {
-        addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider);
+    public synchronized void logProviderReceivedLocations(String provider, int numLocations) {
+        addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations);
     }
 
     /** Logs a location deliver for a client of a location provider. */
-    public synchronized void logProviderDeliveredLocation(String provider,
+    public synchronized void logProviderDeliveredLocations(String provider, int numLocations,
             CallerIdentity identity) {
-        addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, identity);
+        addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity);
     }
 
     /** Logs that the location power save mode has changed. */
@@ -126,10 +126,11 @@
                 return new ProviderUpdateEvent(timeDelta, (String) args[0],
                         (ProviderRequest) args[1]);
             case EVENT_PROVIDER_RECEIVE_LOCATION:
-                return new ProviderReceiveLocationEvent(timeDelta, (String) args[0]);
+                return new ProviderReceiveLocationEvent(timeDelta, (String) args[0],
+                        (Integer) args[1]);
             case EVENT_PROVIDER_DELIVER_LOCATION:
                 return new ProviderDeliverLocationEvent(timeDelta, (String) args[0],
-                        (CallerIdentity) args[1]);
+                        (Integer) args[1], (CallerIdentity) args[2]);
             case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE:
                 return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]);
             default:
@@ -226,33 +227,38 @@
     private static class ProviderReceiveLocationEvent extends LogEvent {
 
         private final String mProvider;
+        private final int mNumLocations;
 
-        private ProviderReceiveLocationEvent(long timeDelta, String provider) {
+        private ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
             super(timeDelta);
             mProvider = provider;
+            mNumLocations = numLocations;
         }
 
         @Override
         public String getLogString() {
-            return mProvider + " provider received location";
+            return mProvider + " provider received location[" + mNumLocations + "]";
         }
     }
 
     private static class ProviderDeliverLocationEvent extends LogEvent {
 
         private final String mProvider;
+        private final int mNumLocations;
         @Nullable private final CallerIdentity mIdentity;
 
-        private ProviderDeliverLocationEvent(long timeDelta, String provider,
+        private ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
                 @Nullable CallerIdentity identity) {
             super(timeDelta);
             mProvider = provider;
+            mNumLocations = numLocations;
             mIdentity = identity;
         }
 
         @Override
         public String getLogString() {
-            return mProvider + " provider delivered location to " + mIdentity;
+            return mProvider + " provider delivered location[" + mNumLocations + "] to "
+                    + mIdentity;
         }
     }
 
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 06cebac..661d38d 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -18,6 +18,8 @@
 
 import static android.provider.Settings.ACTION_VPN_SETTINGS;
 
+import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_VPN;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Notification;
@@ -42,7 +44,6 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.server.ConnectivityService;
 import com.android.server.EventLogTags;
 import com.android.server.connectivity.Vpn;
@@ -256,7 +257,7 @@
 
     private void showNotification(int titleRes, int iconRes) {
         final Notification.Builder builder =
-                new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+                new Notification.Builder(mContext, NOTIFICATION_VPN)
                         .setWhen(0)
                         .setSmallIcon(iconRes)
                         .setContentTitle(mContext.getString(titleRes))
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
index 3b24f46..487482b 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
@@ -23,7 +23,6 @@
 import android.os.ShellCommand;
 import android.provider.Settings;
 
-import java.io.FileInputStream;
 import java.io.InputStream;
 import java.io.PrintWriter;
 
@@ -75,8 +74,9 @@
                 pw.println("Error: can't open input file " + configXmlPath);
                 return -1;
             }
-            final InputStream fileStream = new FileInputStream(pfd.getFileDescriptor());
-            WatchlistConfig.getInstance().setTestMode(fileStream);
+            try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+                WatchlistConfig.getInstance().setTestMode(inputStream);
+            }
             pw.println("Success!");
         } catch (Exception ex) {
             pw.println("Error: " + ex.toString());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f68469f..7afd3db 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19606,7 +19606,7 @@
                         ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
                     }
 
-                    writeRuntimePermissionsForUserLPrTEMP(userId, false);
+                    mSettings.writeRuntimePermissionsForUserLPr(userId, false);
                 }
                 // Regardless of writeSettings we need to ensure that this restriction
                 // state propagation is persisted
@@ -25752,7 +25752,7 @@
         public void writePermissionSettings(int[] userIds, boolean async) {
             synchronized (mLock) {
                 for (int userId : userIds) {
-                    writeRuntimePermissionsForUserLPrTEMP(userId, !async);
+                    mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
                 }
             }
         }
@@ -26401,17 +26401,6 @@
         mSettings.writeLPr();
     }
 
-    /**
-     * Temporary method that wraps mSettings.writeRuntimePermissionsForUserLPr() and calls
-     * mPermissionManager.writeLegacyPermissionStateTEMP() beforehand.
-     *
-     * TODO(zhanghai): This should be removed once we finish migration of permission storage.
-     */
-    private void writeRuntimePermissionsForUserLPrTEMP(@UserIdInt int userId, boolean async) {
-        mPermissionManager.writeLegacyPermissionStateTEMP();
-        mSettings.writeRuntimePermissionsForUserLPr(userId, async);
-    }
-
     @Override
     public IBinder getHoldLockToken() {
         if (!Build.IS_DEBUGGABLE) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index cd9a4e7..71e7358 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5390,6 +5390,8 @@
             mHandler.removeMessages(userId);
             mWriteScheduled.delete(userId);
 
+            mPermissionDataProvider.writeLegacyPermissionStateTEMP();
+
             int version = mVersions.get(userId, INITIAL_VERSION);
 
             String fingerprint = mFingerprints.get(userId);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 3fcf02c..d535f7b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -919,10 +919,10 @@
             } catch (PackageManagerException e) {
                 onInstallationFailure(session, e);
             } catch (Exception e) {
-                final String errorMsg = "Staged install failed due to unhandled exception";
-                Slog.e(TAG, errorMsg, e);
+                Slog.e(TAG, "Staged install failed due to unhandled exception", e);
                 onInstallationFailure(session, new PackageManagerException(
-                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg));
+                        SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+                        "Staged install failed due to unhandled exception: " + e));
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
index 0e790b1..46e4e59 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
@@ -61,4 +61,14 @@
      */
     @NonNull
     int[] getGidsForUid(int uid);
+
+    /**
+     * This method should be in PermissionManagerServiceInternal, however it is made available here
+     * as well to avoid serious performance regression in writePermissionSettings(), which seems to
+     * be a hot spot and we should delay calling this method until wre are actually writing the
+     * file, instead of every time an async write is requested.
+     *
+     * @see PermissionManagerServiceInternal#writeLegacyPermissionStateTEMP()
+     */
+    void writeLegacyPermissionStateTEMP();
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 25a0880..098be92 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2414,6 +2414,9 @@
             params.privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
             params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+            // Setting as trusted overlay to let touches pass through. This is safe because this
+            // window is controlled by the system.
+            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 
             if (!compatInfo.supportsScreen()) {
                 params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 51b00fa..d5ab574b 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -149,11 +149,8 @@
     private static void enforcePermissionForDataDelivery(@NonNull Context context,
             @NonNull Identity identity,
             @NonNull String permission, @NonNull String reason) {
-        // TODO(ytai): We're temporarily ignoring proc state until we have a proper permission that
-        //  represents being able to use the microphone in the background. Otherwise, some of our
-        //  existing use-cases would break.
-        final int status = PermissionUtil.checkPermissionForDataDeliveryIgnoreProcState(context,
-                identity, permission, reason);
+        final int status = PermissionUtil.checkPermissionForDataDelivery(context, identity,
+                permission, reason);
         if (status != PermissionChecker.PERMISSION_GRANTED) {
             throw new SecurityException(
                     String.format("Failed to obtain permission %s for identity %s", permission,
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 98061b5..abcba5d 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -549,6 +549,11 @@
 
     private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
         UserState userState = getOrCreateUserStateLocked(userId);
+        return getSessionStateLocked(sessionToken, callingUid, userState);
+    }
+
+    private SessionState getSessionStateLocked(IBinder sessionToken,
+            int callingUid, UserState userState) {
         SessionState sessionState = userState.sessionStateMap.get(sessionToken);
         if (sessionState == null) {
             throw new SessionNotFoundException("Session state not found for token " + sessionToken);
@@ -1224,7 +1229,7 @@
             try {
                 synchronized (mLock) {
                     if (userId != mCurrentUserId && !isRecordingSession) {
-                        // A non-recording session of a backgroud (non-current) user
+                        // A non-recording session of a background (non-current) user
                         // should not be created.
                         // Let the client get onConnectionFailed callback for this case.
                         sendSessionTokenToClientLocked(client, inputId, null, null, seq);
@@ -1436,12 +1441,11 @@
                         getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
                                 channelUri, params);
                         UserState userState = getOrCreateUserStateLocked(resolvedUserId);
-                        SessionState sessionState = userState.sessionStateMap.get(sessionToken);
-                        if (sessionState != null) {
-                            sessionState.isCurrent = true;
-                            sessionState.currentChannel = channelUri;
-                            notifyCurrentChannelInfosUpdatedLocked(userState);
-                        }
+                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+                                userState);
+                        sessionState.isCurrent = true;
+                        sessionState.currentChannel = channelUri;
+                        notifyCurrentChannelInfosUpdatedLocked(userState);
                         if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
                             // Do not log the watch history for passthrough inputs.
                             return;
@@ -2028,10 +2032,8 @@
                         SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
                                 new SessionState[2]);
                         // Check if there is a wrapper input.
-                        if (sessionStates[0].hardwareSessionToken != null
-                                || sessionStates[1].hardwareSessionToken != null) {
-                            return true;
-                        }
+                        return sessionStates[0].hardwareSessionToken != null
+                                || sessionStates[1].hardwareSessionToken != null;
                     }
                     return false;
                 }
@@ -2111,7 +2113,7 @@
          * Add a hardware device in the TvInputHardwareManager for CTS testing
          * purpose.
          *
-         * @param device id of the adding hardware device.
+         * @param deviceId  the id of the adding hardware device.
          */
         @Override
         public void addHardwareDevice(int deviceId) {
@@ -2123,14 +2125,13 @@
                         .hdmiPortId(0)
                         .build();
             mTvInputHardwareManager.onDeviceAvailable(info, null);
-            return;
         }
 
         /**
          * Remove a hardware device in the TvInputHardwareManager for CTS testing
          * purpose.
          *
-         * @param device id of the removing hardware device.
+         * @param deviceId the id of the removing hardware device.
          */
         @Override
         public void removeHardwareDevice(int deviceId) {
@@ -2254,7 +2255,6 @@
                         pw.println("userId: " + session.userId);
                         pw.println("sessionToken: " + session.sessionToken);
                         pw.println("session: " + session.session);
-                        pw.println("logUri: " + session.logUri);
                         pw.println("hardwareSessionToken: " + session.hardwareSessionToken);
                         pw.decreaseIndent();
                     }
@@ -2264,7 +2264,7 @@
                     pw.increaseIndent();
                     int n = userState.mCallbacks.beginBroadcast();
                     for (int j = 0; j < n; ++j) {
-                        pw.println(userState.mCallbacks.getRegisteredCallbackItem(j).toString());
+                        pw.println(userState.mCallbacks.getRegisteredCallbackItem(j));
                     }
                     userState.mCallbacks.finishBroadcast();
                     pw.decreaseIndent();
@@ -2363,7 +2363,7 @@
 
         // A list of callbacks.
         private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
-                new RemoteCallbackList<ITvInputManagerCallback>();
+                new RemoteCallbackList<>();
 
         private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
                 new HashMap<>();
@@ -2474,7 +2474,6 @@
         private final int userId;
         private final IBinder sessionToken;
         private ITvInputSession session;
-        private Uri logUri;
         // Not null if this session represents an external device connected to a hardware TV input.
         private IBinder hardwareSessionToken;
 
@@ -3024,7 +3023,7 @@
                     IBinder sessionToken = (IBinder) args.arg5;
 
                     ContentValues values = new ContentValues();
-                    values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
+                    values.put(TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME, packageName);
                     values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
                             watchStartTime);
                     values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
diff --git a/services/core/java/com/android/server/utils/quota/QuotaTracker.java b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
index c1dfcf7..7f44618 100644
--- a/services/core/java/com/android/server/utils/quota/QuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
@@ -149,9 +149,13 @@
     @VisibleForTesting
     static final long MAX_WINDOW_SIZE_MS = 30 * 24 * 60 * MINUTE_IN_MILLIS; // 1 month
 
-    /** The minimum time any window size can be. */
+    /**
+     * The minimum time any window size can be. A minimum window size helps to avoid CPU
+     * churn/looping in cases where there are registered listeners for when UPTCs go in and out of
+     * quota.
+     */
     @VisibleForTesting
-    static final long MIN_WINDOW_SIZE_MS = 30_000; // 30 seconds
+    static final long MIN_WINDOW_SIZE_MS = 20_000;
 
     QuotaTracker(@NonNull Context context, @NonNull Categorizer categorizer,
             @NonNull Injector injector) {
@@ -622,6 +626,9 @@
 
     /** Dump state in text format. */
     public void dump(final IndentingPrintWriter pw) {
+        pw.println("QuotaTracker:");
+        pw.increaseIndent();
+
         synchronized (mLock) {
             pw.println("Is enabled: " + mIsEnabled);
             pw.println("Is global quota free: " + mIsQuotaFree);
@@ -646,6 +653,8 @@
             }
             pw.decreaseIndent();
         }
+
+        pw.decreaseIndent();
     }
 
     /**
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
new file mode 100644
index 0000000..42a0a706
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -0,0 +1,158 @@
+/*
+ * 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.vibrator;
+
+import android.content.Context;
+import android.hardware.vibrator.V1_0.EffectStrength;
+import android.os.IExternalVibratorService;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.Slog;
+import android.util.SparseArray;
+
+/** Controls vibration scaling. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public final class VibrationScaler {
+    private static final String TAG = "VibrationScaler";
+
+    // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
+    // and the default intensity for that type of vibration (i.e. current - default).
+    private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
+    private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
+    private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
+    private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
+    private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
+    private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
+
+    // Scale factors for each level.
+    private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
+    private static final float SCALE_FACTOR_LOW = 0.8f;
+    private static final float SCALE_FACTOR_NONE = 1f;
+    private static final float SCALE_FACTOR_HIGH = 1.2f;
+    private static final float SCALE_FACTOR_VERY_HIGH = 1.4f;
+
+    // A mapping from the intensity adjustment to the scaling to apply, where the intensity
+    // adjustment is defined as the delta between the default intensity level and the user selected
+    // intensity level. It's important that we apply the scaling on the delta between the two so
+    // that the default intensity level applies no scaling to application provided effects.
+    private final SparseArray<ScaleLevel> mScaleLevels;
+    private final VibrationSettings mSettingsController;
+    private final int mDefaultVibrationAmplitude;
+
+    public VibrationScaler(Context context, VibrationSettings settingsController) {
+        mSettingsController = settingsController;
+        mDefaultVibrationAmplitude = context.getResources().getInteger(
+                com.android.internal.R.integer.config_defaultVibrationAmplitude);
+
+        mScaleLevels = new SparseArray<>();
+        mScaleLevels.put(SCALE_VERY_LOW, new ScaleLevel(SCALE_FACTOR_VERY_LOW));
+        mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_FACTOR_LOW));
+        mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_FACTOR_NONE));
+        mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_FACTOR_HIGH));
+        mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_FACTOR_VERY_HIGH));
+    }
+
+    /**
+     * Calculates the scale to be applied to external vibration with given usage.
+     *
+     * @param usageHint one of VibrationAttributes.USAGE_*
+     * @return one of IExternalVibratorService.SCALE_*
+     */
+    public int getExternalVibrationScale(int usageHint) {
+        int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
+        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
+        int scaleLevel = currentIntensity - defaultIntensity;
+
+        if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
+            return scaleLevel;
+        } else {
+            // Something about our scaling has gone wrong, so just play with no scaling.
+            Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
+                    + scaleLevel + " for vibration with usage " + usageHint);
+            return SCALE_NONE;
+        }
+    }
+
+    /**
+     * Scale a {@link VibrationEffect} based on the given usage hint for this vibration.
+     *
+     * @param effect    the effect to be scaled
+     * @param usageHint one of VibrationAttributes.USAGE_*
+     * @return The same given effect, if no changes were made, or a new {@link VibrationEffect} with
+     * resolved and scaled amplitude
+     */
+    public <T extends VibrationEffect> T scale(VibrationEffect effect, int usageHint) {
+        if (effect instanceof VibrationEffect.Prebaked) {
+            // Prebaked effects are always just a direct translation to EffectStrength.
+            int intensity = mSettingsController.getCurrentIntensity(usageHint);
+            int newStrength = intensityToEffectStrength(intensity);
+            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+
+            if (prebaked.getEffectStrength() == newStrength) {
+                return (T) prebaked;
+            }
+
+            return (T) new VibrationEffect.Prebaked(
+                    prebaked.getId(), prebaked.shouldFallback(), newStrength);
+        }
+
+        effect = effect.resolve(mDefaultVibrationAmplitude);
+        int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
+        int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
+        ScaleLevel scale = mScaleLevels.get(currentIntensity - defaultIntensity);
+
+        if (scale == null) {
+            // Something about our scaling has gone wrong, so just play with no scaling.
+            Slog.e(TAG, "No configured scaling level!"
+                    + " (current=" + currentIntensity + ", default= " + defaultIntensity + ")");
+            return (T) effect;
+        }
+
+        return effect.scale(scale.factor);
+    }
+
+
+
+    /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
+    private static int intensityToEffectStrength(int intensity) {
+        switch (intensity) {
+            case Vibrator.VIBRATION_INTENSITY_LOW:
+                return EffectStrength.LIGHT;
+            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
+                return EffectStrength.MEDIUM;
+            case Vibrator.VIBRATION_INTENSITY_HIGH:
+                return EffectStrength.STRONG;
+            default:
+                Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
+                return EffectStrength.STRONG;
+        }
+    }
+
+    /** Represents the scale that must be applied to a vibration effect intensity. */
+    private static final class ScaleLevel {
+        public final float factor;
+
+        ScaleLevel(float factor) {
+            this.factor = factor;
+        }
+
+        @Override
+        public String toString() {
+            return "ScaleLevel{factor=" + factor + "}";
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
new file mode 100644
index 0000000..ad2b3354
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -0,0 +1,284 @@
+/*
+ * 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.vibrator;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.VibrationAttributes;
+import android.os.Vibrator;
+import android.provider.Settings;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Controls all the system settings related to vibration. */
+// TODO(b/159207608): Make this package-private once vibrator services are moved to this package
+public final class VibrationSettings {
+    private static final String TAG = "VibrationSettings";
+
+    /** Listener for changes on vibration settings. */
+    public interface OnVibratorSettingsChanged {
+        /** Callback triggered when any of the vibrator settings change. */
+        void onChange();
+    }
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final Vibrator mVibrator;
+    private final AudioManager mAudioManager;
+    private final SettingsObserver mSettingObserver;
+
+    @GuardedBy("mLock")
+    private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>();
+
+    @GuardedBy("mLock")
+    private boolean mVibrateInputDevices;
+    @GuardedBy("mLock")
+    private boolean mVibrateWhenRinging;
+    @GuardedBy("mLock")
+    private boolean mApplyRampingRinger;
+    @GuardedBy("mLock")
+    private int mZenMode;
+    @GuardedBy("mLock")
+    private int mHapticFeedbackIntensity;
+    @GuardedBy("mLock")
+    private int mNotificationIntensity;
+    @GuardedBy("mLock")
+    private int mRingIntensity;
+
+    public VibrationSettings(Context context, Handler handler) {
+        mContext = context;
+        mVibrator = context.getSystemService(Vibrator.class);
+        mAudioManager = context.getSystemService(AudioManager.class);
+        mSettingObserver = new SettingsObserver(handler);
+
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
+        registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_WHEN_RINGING));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.APPLY_RAMPING_RINGER));
+        registerSettingsObserver(Settings.Global.getUriFor(Settings.Global.ZEN_MODE));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY));
+        registerSettingsObserver(
+                Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY));
+
+        // Update with current values from settings.
+        updateSettings();
+    }
+
+    /**
+     * Add listener to vibrator settings changes. This will trigger the listener with current state
+     * immediately and every time one of the settings change.
+     */
+    public void addListener(OnVibratorSettingsChanged listener) {
+        synchronized (mLock) {
+            if (!mListeners.contains(listener)) {
+                mListeners.add(listener);
+            }
+        }
+    }
+
+    /** Remove listener to vibrator settings. */
+    public void removeListener(OnVibratorSettingsChanged listener) {
+        synchronized (mLock) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Return default vibration intensity for given usage.
+     *
+     * @param usageHint one of VibrationAttributes.USAGE_*
+     * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
+     */
+    public int getDefaultIntensity(int usageHint) {
+        if (isRingtone(usageHint)) {
+            return mVibrator.getDefaultRingVibrationIntensity();
+        } else if (isNotification(usageHint)) {
+            return mVibrator.getDefaultNotificationVibrationIntensity();
+        } else if (isHapticFeedback(usageHint)) {
+            return mVibrator.getDefaultHapticFeedbackIntensity();
+        } else if (isAlarm(usageHint)) {
+            return Vibrator.VIBRATION_INTENSITY_HIGH;
+        } else {
+            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
+        }
+    }
+
+    /**
+     * Return the current vibration intensity set for given usage at the user settings.
+     *
+     * @param usageHint one of VibrationAttributes.USAGE_*
+     * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_*
+     */
+    public int getCurrentIntensity(int usageHint) {
+        synchronized (mLock) {
+            if (isRingtone(usageHint)) {
+                return mRingIntensity;
+            } else if (isNotification(usageHint)) {
+                return mNotificationIntensity;
+            } else if (isHapticFeedback(usageHint)) {
+                return mHapticFeedbackIntensity;
+            } else if (isAlarm(usageHint)) {
+                return Vibrator.VIBRATION_INTENSITY_HIGH;
+            } else {
+                return Vibrator.VIBRATION_INTENSITY_MEDIUM;
+            }
+        }
+    }
+
+    /**
+     * Return {@code true} if the device should vibrate for ringtones.
+     *
+     * <p>This checks the current {@link AudioManager#getRingerMode()} against user settings for
+     * vibrations while ringing.
+     */
+    public boolean shouldVibrateForRingtone() {
+        int ringerMode = mAudioManager.getRingerModeInternal();
+        synchronized (mLock) {
+            if (mVibrateWhenRinging) {
+                return ringerMode != AudioManager.RINGER_MODE_SILENT;
+            } else if (mApplyRampingRinger) {
+                return ringerMode != AudioManager.RINGER_MODE_SILENT;
+            } else {
+                return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+            }
+        }
+    }
+
+    /** Return {@code true} if input devices should vibrate instead of this device. */
+    public boolean shouldVibrateInputDevices() {
+        return mVibrateInputDevices;
+    }
+
+    /** Return {@code true} if setting for {@link Settings.Global#ZEN_MODE} is not OFF. */
+    public boolean isInZenMode() {
+        return mZenMode != Settings.Global.ZEN_MODE_OFF;
+    }
+
+    private static boolean isNotification(int usageHint) {
+        return usageHint == VibrationAttributes.USAGE_NOTIFICATION;
+    }
+
+    private static boolean isRingtone(int usageHint) {
+        return usageHint == VibrationAttributes.USAGE_RINGTONE;
+    }
+
+    private static boolean isHapticFeedback(int usageHint) {
+        return usageHint == VibrationAttributes.USAGE_TOUCH;
+    }
+
+    private static boolean isAlarm(int usageHint) {
+        return usageHint == VibrationAttributes.USAGE_ALARM;
+    }
+
+    /** Updates all vibration settings and triggers registered listeners. */
+    @VisibleForTesting
+    public void updateSettings() {
+        List<OnVibratorSettingsChanged> currentListeners;
+        synchronized (mLock) {
+            mVibrateWhenRinging = getSystemSetting(Settings.System.VIBRATE_WHEN_RINGING, 0) != 0;
+            mApplyRampingRinger = getGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0) != 0;
+            mHapticFeedbackIntensity = getSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                    mVibrator.getDefaultHapticFeedbackIntensity());
+            mNotificationIntensity = getSystemSetting(
+                    Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                    mVibrator.getDefaultNotificationVibrationIntensity());
+            mRingIntensity = getSystemSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                    mVibrator.getDefaultRingVibrationIntensity());
+            mVibrateInputDevices = getSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0) > 0;
+            mZenMode = getGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+            currentListeners = new ArrayList<>(mListeners);
+        }
+
+        for (OnVibratorSettingsChanged listener : currentListeners) {
+            listener.onChange();
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "VibrationSettings{"
+                + "mVibrateInputDevices=" + mVibrateInputDevices
+                + ", mVibrateWhenRinging=" + mVibrateWhenRinging
+                + ", mApplyRampingRinger=" + mApplyRampingRinger
+                + ", mZenMode=" + Settings.Global.zenModeToString(mZenMode)
+                + ", mHapticFeedbackIntensity="
+                +  intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH))
+                + ", mHapticFeedbackDefaultIntensity="
+                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_TOUCH))
+                + ", mNotificationIntensity="
+                + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION))
+                + ", mNotificationDefaultIntensity="
+                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION))
+                + ", mRingIntensity="
+                + intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE))
+                + ", mRingDefaultIntensity="
+                + intensityToString(getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE))
+                + '}';
+    }
+
+    private static String intensityToString(int intensity) {
+        switch (intensity) {
+            case Vibrator.VIBRATION_INTENSITY_OFF:
+                return "OFF";
+            case Vibrator.VIBRATION_INTENSITY_LOW:
+                return "LOW";
+            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
+                return "MEDIUM";
+            case Vibrator.VIBRATION_INTENSITY_HIGH:
+                return "HIGH";
+            default:
+                return "UNKNOWN INTENSITY " + intensity;
+        }
+    }
+
+    private int getSystemSetting(String settingName, int defaultValue) {
+        return Settings.System.getIntForUser(mContext.getContentResolver(),
+                settingName, defaultValue, UserHandle.USER_CURRENT);
+    }
+
+    private int getGlobalSetting(String settingName, int defaultValue) {
+        return Settings.Global.getInt(mContext.getContentResolver(), settingName, defaultValue);
+    }
+
+    private void registerSettingsObserver(Uri settingUri) {
+        mContext.getContentResolver().registerContentObserver(
+                settingUri, /* notifyForDescendants= */ true, mSettingObserver,
+                UserHandle.USER_ALL);
+    }
+
+    /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
+    private final class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            updateSettings();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4b5518c..33df8b8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -445,7 +445,6 @@
     private Task task;              // the task this is in.
     private long createTime = System.currentTimeMillis();
     long lastVisibleTime;         // last time this activity became visible
-    long cpuTimeAtResume;         // the cpu time of host process at the time of resuming activity
     long pauseTime;               // last time we started pausing the activity
     long launchTickTime;          // base time for launch tick messages
     long topResumedStateLossTime; // last time we reported top resumed state loss to an activity
@@ -5010,16 +5009,6 @@
         resumeKeyDispatchingLocked();
         final Task stack = getRootTask();
         mStackSupervisor.mNoAnimActivities.clear();
-
-        // Mark the point when the activity is resuming
-        // TODO: To be more accurate, the mark should be before the onCreate,
-        //       not after the onResume. But for subsequent starts, onResume is fine.
-        if (hasProcess()) {
-            cpuTimeAtResume = app.getCpuTime();
-        } else {
-            cpuTimeAtResume = 0; // Couldn't get the cpu time of process
-        }
-
         returningOptions = null;
 
         if (canTurnScreenOn()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 33819a9..d13b8d4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1195,7 +1195,23 @@
             }
         }
 
-        mService.onStartActivitySetDidAppSwitch();
+        if (mService.getBalAppSwitchesProtectionEnabled()) {
+            // Only allow app switching to be resumed if activity is not a restricted background
+            // activity and target app is not home process, otherwise any background activity
+            // started in background task can stop home button protection mode.
+            // As the targeted app is not a home process and we don't need to wait for the 2nd
+            // activity to be started to resume app switching, we can just enable app switching
+            // directly.
+            WindowProcessController homeProcess = mService.mHomeProcess;
+            boolean isHomeProcess = homeProcess != null
+                    && aInfo.applicationInfo.uid == homeProcess.mUid;
+            if (!restrictedBgActivity && !isHomeProcess) {
+                mService.resumeAppSwitches();
+            }
+        } else {
+            mService.onStartActivitySetDidAppSwitch();
+        }
+
         mController.doPendingActivityLaunches(false);
 
         mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
@@ -1260,6 +1276,20 @@
             return false;
         }
 
+        // Always allow home application to start activities.
+        if (mService.mHomeProcess != null && callingUid == mService.mHomeProcess.mUid) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(TAG, "Activity start allowed for home app callingUid (" + callingUid + ")");
+            }
+            return false;
+        }
+
+        // App switching will be allowed if BAL app switching flag is not enabled, or if
+        // its app switching rule allows it.
+        // This is used to block background activity launch even if the app is still
+        // visible to user after user clicking home button.
+        final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed();
+
         // don't abort if the callingUid has a visible window or is a persistent system process
         final int callingUidProcState = mService.getUidState(callingUid);
         final boolean callingUidHasAnyVisibleWindow =
@@ -1269,7 +1299,8 @@
                 || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
         final boolean isCallingUidPersistentSystemProcess =
                 callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-        if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
+        if ((appSwitchAllowed && callingUidHasAnyVisibleWindow)
+                || isCallingUidPersistentSystemProcess) {
             if (DEBUG_ACTIVITY_STARTS) {
                 Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
                         + ", isCallingUidPersistentSystemProcess = "
@@ -1295,6 +1326,7 @@
                         || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
         if (realCallingUid != callingUid) {
             // don't abort if the realCallingUid has a visible window
+            // TODO(b/171459802): We should check appSwitchAllowed also
             if (realCallingUidHasAnyVisibleWindow) {
                 if (DEBUG_ACTIVITY_STARTS) {
                     Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
@@ -1376,7 +1408,7 @@
         // don't abort if the callerApp or other processes of that uid are allowed in any way
         if (callerApp != null) {
             // first check the original calling process
-            if (callerApp.areBackgroundActivityStartsAllowed()) {
+            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
                 if (DEBUG_ACTIVITY_STARTS) {
                     Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
                             + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
@@ -1389,7 +1421,8 @@
             if (uidProcesses != null) {
                 for (int i = uidProcesses.size() - 1; i >= 0; i--) {
                     final WindowProcessController proc = uidProcesses.valueAt(i);
-                    if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) {
+                    if (proc != callerApp
+                            && proc.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
                         if (DEBUG_ACTIVITY_STARTS) {
                             Slog.d(TAG,
                                     "Background activity start allowed: process " + proc.getPid()
@@ -1403,6 +1436,8 @@
         // anything that has fallen through would currently be aborted
         Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
                 + "; callingUid: " + callingUid
+                + "; appSwitchAllowed: " + appSwitchAllowed
+                + "; balAppSwitchEnabled: " + mService.getBalAppSwitchesProtectionEnabled()
                 + "; isCallingUidForeground: " + isCallingUidForeground
                 + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
                 + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 73c4713..84255c7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -161,9 +161,11 @@
 import android.app.admin.DevicePolicyCache;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
+import android.app.compat.CompatChanges;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.EnterPipRequestedItem;
 import android.app.usage.UsageStatsManagerInternal;
+import android.compat.annotation.ChangeId;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -214,6 +216,7 @@
 import android.os.WorkSource;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.dreams.DreamActivity;
 import android.service.voice.IVoiceInteractionSession;
@@ -342,6 +345,12 @@
     /** This activity is being relaunched due to a free-resize operation. */
     public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
 
+    /**
+     * Apps are blocked from starting activities in the foreground after the user presses home.
+     */
+    public static final String BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG =
+            "am_block_activity_starts_after_home";
+
     Context mContext;
 
     /**
@@ -366,6 +375,8 @@
     PendingIntentController mPendingIntentController;
     IntentFirewall mIntentFirewall;
 
+    final VisibleActivityProcessTracker mVisibleActivityProcessTracker;
+
     /* Global service lock used by the package the owns this service. */
     final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
     /**
@@ -394,6 +405,7 @@
     volatile WindowProcessController mHeavyWeightProcess;
     boolean mHasHeavyWeightFeature;
     boolean mHasLeanbackFeature;
+    boolean mBlockActivityAfterHomeEnabled;
     /** The process of the top most activity. */
     volatile WindowProcessController mTopApp;
     /**
@@ -741,6 +753,7 @@
         mSystemThread = ActivityThread.currentActivityThread();
         mUiContext = mSystemThread.getSystemUiContext();
         mLifecycleManager = new ClientLifecycleManager();
+        mVisibleActivityProcessTracker = new VisibleActivityProcessTracker(this);
         mInternal = new LocalService();
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
         mWindowOrganizerController = new WindowOrganizerController(this);
@@ -756,6 +769,9 @@
             mVrController.onSystemReady();
             mRecentTasks.onSystemReadyLocked();
             mStackSupervisor.onSystemReady();
+            mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, false);
         }
     }
 
@@ -2627,8 +2643,35 @@
         throw new SecurityException(msg);
     }
 
+    /**
+     * Return true if app switch protection will be handled by background activity launch logic.
+     */
+    boolean getBalAppSwitchesProtectionEnabled() {
+         return mBlockActivityAfterHomeEnabled;
+    }
+
+    /**
+     * Return true if app switching is allowed.
+     */
+    boolean getBalAppSwitchesAllowed() {
+        if (getBalAppSwitchesProtectionEnabled()) {
+            // Apps no longer able to start BAL again until app switching is resumed.
+            return mAppSwitchesAllowedTime == 0;
+        } else {
+            // Legacy behavior, BAL logic won't block app switching.
+            return true;
+        }
+    }
+
     boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
             int callingPid, int callingUid, String name) {
+
+        // Background activity launch logic replaces app switching protection, so allow
+        // apps to start activity here now.
+        if (getBalAppSwitchesProtectionEnabled()) {
+            return true;
+        }
+
         if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
             return true;
         }
@@ -4663,7 +4706,10 @@
             mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME;
             mLastStopAppSwitchesTime = SystemClock.uptimeMillis();
             mDidAppSwitch = false;
-            getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+            // If BAL app switching enabled, app switches are blocked not delayed.
+            if (!getBalAppSwitchesProtectionEnabled()) {
+                getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+            }
         }
     }
 
@@ -6103,16 +6149,7 @@
 
         @Override
         public boolean hasResumedActivity(int uid) {
-            synchronized (mGlobalLock) {
-                final ArraySet<WindowProcessController> processes = mProcessMap.getProcesses(uid);
-                for (int i = 0, n = processes.size(); i < n; i++) {
-                    final WindowProcessController process = processes.valueAt(i);
-                    if (process.hasResumedActivity()) {
-                        return true;
-                    }
-                }
-            }
-            return false;
+            return mVisibleActivityProcessTracker.hasResumedActivity(uid);
         }
 
         public void setBackgroundActivityStartCallback(
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 3eac1be..627af91 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -49,6 +49,7 @@
     static final int MSG_DRAG_END_TIMEOUT = 0;
     static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
     static final int MSG_ANIMATION_END = 2;
+    static final int MSG_REMOVE_DRAG_SURFACE_TIMEOUT = 3;
 
     /**
      * Drag state per operation.
@@ -384,6 +385,14 @@
                     }
                     break;
                 }
+
+                case MSG_REMOVE_DRAG_SURFACE_TIMEOUT: {
+                    synchronized (mService.mGlobalLock) {
+                        mService.mTransactionFactory.get()
+                                .reparent((SurfaceControl) msg.obj, null).apply();
+                    }
+                    break;
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 8c80205..e7d8ad6 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -23,6 +23,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
 import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
+import static com.android.server.wm.DragDropController.MSG_REMOVE_DRAG_SURFACE_TIMEOUT;
 import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -59,6 +60,7 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
+import com.android.internal.os.SomeArgs;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.view.IDragAndDropPermissions;
 import com.android.server.LocalServices;
@@ -248,6 +250,9 @@
         if (mSurfaceControl != null) {
             if (!mRelinquishDragSurface) {
                 mTransaction.reparent(mSurfaceControl, null).apply();
+            } else {
+                mDragDropController.sendTimeoutMessage(MSG_REMOVE_DRAG_SURFACE_TIMEOUT,
+                        mSurfaceControl);
             }
             mSurfaceControl = null;
         }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index e83151d..a82133d 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -151,6 +151,7 @@
             // TODO: Ideally, we should wait for the animation to finish so previous window can
             // animate-out as new one animates-in.
             mWin.cancelAnimation();
+            mWin.mPendingPositionChanged = null;
         }
         ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
         mWin = win;
@@ -181,7 +182,9 @@
      * window gets laid out.
      */
     void updateSourceFrame() {
-        if (mWin == null) {
+        if (mWin == null || mWin.mGivenInsetsPending) {
+            // If the given insets are pending, they are not reliable for now. The source frame
+            // should be updated after the new given insets are sent to window manager.
             return;
         }
 
@@ -238,19 +241,45 @@
             return;
         }
 
-        setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
-                && !mWin.mGivenInsetsPending);
+        setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
         updateSourceFrame();
         if (mControl != null) {
             final Rect frame = mWin.getWindowFrames().mFrame;
             if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
-                // The leash has been stale, we need to create a new one for the client.
-                updateControlForTarget(mControlTarget, true /* force */);
+                if (!mWin.getWindowFrames().didFrameSizeChange()) {
+                    updateLeashPosition(frame, -1 /* frameNumber */);
+                } else if (mWin.mInRelayout) {
+                    updateLeashPosition(frame, mWin.getFrameNumber());
+                } else {
+                    mWin.mPendingPositionChanged = this;
+                }
                 mStateController.notifyControlChanged(mControlTarget);
             }
         }
     }
 
+    void updateLeashPosition(Rect frame, long frameNumber) {
+        if (mControl == null) {
+            return;
+        }
+        final SurfaceControl leash = mControl.getLeash();
+        if (leash != null) {
+            final Transaction t = mDisplayContent.getPendingTransaction();
+            Point position = new Point();
+            mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
+            t.setPosition(leash, position.x, position.y);
+            deferTransactionUntil(t, leash, frameNumber);
+        }
+    }
+
+    private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
+        if (frameNumber >= 0) {
+            final SurfaceControl barrier = mWin.getClientViewRootSurface();
+            t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
+            t.deferTransactionUntil(leash, barrier, frameNumber);
+        }
+    }
+
     /**
      * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
      */
@@ -305,14 +334,12 @@
         final SurfaceControl leash = mAdapter.mCapturedLeash;
         final long frameNumber = mFinishSeamlessRotateFrameNumber;
         mFinishSeamlessRotateFrameNumber = -1;
-        if (frameNumber >= 0 && mWin.mHasSurface && leash != null) {
+        if (mWin.mHasSurface && leash != null) {
             // We just finished the seamless rotation. We don't want to change the position or the
             // window crop of the surface controls (including the leash) until the client finishes
             // drawing the new frame of the new orientation. Although we cannot defer the reparent
             // operation, it is fine, because reparent won't cause any visual effect.
-            final SurfaceControl barrier = mWin.getClientViewRootSurface();
-            t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
-            t.deferTransactionUntil(leash, barrier, frameNumber);
+            deferTransactionUntil(t, leash, frameNumber);
         }
         mControlTarget = target;
         updateVisibility();
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 773bf54..9d70fd7 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -193,6 +193,8 @@
                 state.removeSource(ITYPE_STATUS_BAR);
                 state.removeSource(ITYPE_CLIMATE_BAR);
                 state.removeSource(ITYPE_CAPTION_BAR);
+                state.removeSource(ITYPE_NAVIGATION_BAR);
+                state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
             }
 
             // Status bar doesn't get influenced by caption bar
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0b2ba87..86f1cf7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -162,7 +162,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -4072,6 +4071,10 @@
         info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
         info.configuration.setTo(getConfiguration());
+        // Update to the task's current activity type and windowing mode which may differ from the
+        // window configuration
+        info.configuration.windowConfiguration.setActivityType(getActivityType());
+        info.configuration.windowConfiguration.setWindowingMode(getWindowingMode());
         info.token = mRemoteToken.toWindowContainerToken();
 
         //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
@@ -5689,19 +5692,6 @@
 
         if (prev != null) {
             prev.resumeKeyDispatchingLocked();
-
-            if (prev.hasProcess() && prev.cpuTimeAtResume > 0) {
-                final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
-                if (diff > 0) {
-                    final Runnable r = PooledLambda.obtainRunnable(
-                            ActivityManagerInternal::updateForegroundTimeIfOnBattery,
-                            mAtmService.mAmInternal, prev.info.packageName,
-                            prev.info.applicationInfo.uid,
-                            diff);
-                    mAtmService.mH.post(r);
-                }
-            }
-            prev.cpuTimeAtResume = 0; // reset it
         }
 
         mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java b/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java
new file mode 100644
index 0000000..7f62630
--- /dev/null
+++ b/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.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.wm;
+
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A quick lookup for all processes with visible activities. It also tracks the CPU usage of
+ * host process with foreground (resumed) activity.
+ */
+class VisibleActivityProcessTracker {
+    @GuardedBy("mProcMap")
+    private final ArrayMap<WindowProcessController, CpuTimeRecord> mProcMap = new ArrayMap<>();
+    final Executor mBgExecutor = BackgroundThread.getExecutor();
+    final ActivityTaskManagerService mAtms;
+
+    VisibleActivityProcessTracker(ActivityTaskManagerService atms) {
+        mAtms = atms;
+    }
+
+    /** Called when any activity is visible in the process that didn't have one. */
+    void onAnyActivityVisible(WindowProcessController wpc) {
+        final CpuTimeRecord r = new CpuTimeRecord(wpc);
+        synchronized (mProcMap) {
+            mProcMap.put(wpc, r);
+        }
+        if (wpc.hasResumedActivity()) {
+            r.mShouldGetCpuTime = true;
+            mBgExecutor.execute(r);
+        }
+    }
+
+    /** Called when all visible activities of the process are no longer visible. */
+    void onAllActivitiesInvisible(WindowProcessController wpc) {
+        final CpuTimeRecord r = removeProcess(wpc);
+        if (r != null && r.mShouldGetCpuTime) {
+            mBgExecutor.execute(r);
+        }
+    }
+
+    /** Called when an activity is resumed on a process which is known to have visible activity. */
+    void onActivityResumedWhileVisible(WindowProcessController wpc) {
+        final CpuTimeRecord r;
+        synchronized (mProcMap) {
+            r = mProcMap.get(wpc);
+        }
+        if (r != null && !r.mShouldGetCpuTime) {
+            r.mShouldGetCpuTime = true;
+            mBgExecutor.execute(r);
+        }
+    }
+
+    boolean hasResumedActivity(int uid) {
+        synchronized (mProcMap) {
+            for (int i = mProcMap.size() - 1; i >= 0; i--) {
+                final WindowProcessController wpc = mProcMap.keyAt(i);
+                if (wpc.mUid == uid && wpc.hasResumedActivity()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    CpuTimeRecord removeProcess(WindowProcessController wpc) {
+        synchronized (mProcMap) {
+            return mProcMap.remove(wpc);
+        }
+    }
+
+    /**
+     * Get CPU time in background thread because it will access proc files or the lock of cpu
+     * tracker is held by a background thread.
+     */
+    private class CpuTimeRecord implements Runnable {
+        private final WindowProcessController mProc;
+        private long mCpuTime;
+        private boolean mHasStartCpuTime;
+        boolean mShouldGetCpuTime;
+
+        CpuTimeRecord(WindowProcessController wpc) {
+            mProc = wpc;
+        }
+
+        @Override
+        public void run() {
+            if (mProc.getPid() == 0) {
+                // The process is dead.
+                return;
+            }
+            if (!mHasStartCpuTime) {
+                mHasStartCpuTime = true;
+                mCpuTime = mProc.getCpuTime();
+            } else {
+                final long diff = mProc.getCpuTime() - mCpuTime;
+                if (diff > 0) {
+                    mAtms.mAmInternal.updateForegroundTimeIfOnBattery(
+                            mProc.mInfo.packageName, mProc.mInfo.uid, diff);
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 259dee4..81122ac 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -203,7 +203,7 @@
     /**
      * @return true if the width or height has changed since last reported to the client.
      */
-    private boolean didFrameSizeChange() {
+    boolean didFrameSizeChange() {
         return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e7d9e6b..01abbe2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2191,6 +2191,11 @@
                 win.finishSeamlessRotation(false /* timeout */);
             }
 
+            if (win.mPendingPositionChanged != null) {
+                win.mPendingPositionChanged.updateLeashPosition(win.getFrame(), frameNumber);
+                win.mPendingPositionChanged = null;
+            }
+
             if (mUseBLASTSync && win.useBLASTSync()) {
                 result |= RELAYOUT_RES_BLAST_SYNC;
             }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5bfa662..bb76a0d 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -137,8 +137,6 @@
     private volatile String mRequiredAbi;
     // Running any services that are foreground?
     private volatile boolean mHasForegroundServices;
-    // Running any activities that are foreground?
-    private volatile boolean mHasForegroundActivities;
     // Are there any client services with activities?
     private volatile boolean mHasClientActivities;
     // Is this process currently showing a non-activity UI that the user is interacting with?
@@ -226,10 +224,12 @@
     private final BackgroundActivityStartCallback mBackgroundActivityStartCallback;
 
     // The bits used for mActivityStateFlags.
-    private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 0x10000000;
-    private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 0x20000000;
-    private static final int ACTIVITY_STATE_FLAG_IS_STOPPING = 0x40000000;
-    private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 0x80000000;
+    private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16;
+    private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17;
+    private static final int ACTIVITY_STATE_FLAG_IS_STOPPING = 1 << 18;
+    private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 1 << 19;
+    private static final int ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE = 1 << 20;
+    private static final int ACTIVITY_STATE_FLAG_HAS_RESUMED = 1 << 21;
     private static final int ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER = 0x0000ffff;
 
     /**
@@ -281,6 +281,9 @@
             // configuration will update when display is ready.
             if (thread != null) {
                 setLastReportedConfiguration(getConfiguration());
+            } else {
+                // The process is inactive.
+                mAtm.mVisibleActivityProcessTracker.removeProcess(this);
             }
         }
     }
@@ -349,12 +352,10 @@
         return mHasForegroundServices;
     }
 
-    public void setHasForegroundActivities(boolean hasForegroundActivities) {
-        mHasForegroundActivities = hasForegroundActivities;
-    }
-
     boolean hasForegroundActivities() {
-        return mHasForegroundActivities;
+        return mAtm.mTopApp == this || (mActivityStateFlags
+                & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED
+                        | ACTIVITY_STATE_FLAG_IS_STOPPING)) != 0;
     }
 
     public void setHasClientActivities(boolean hasClientActivities) {
@@ -515,29 +516,33 @@
         }
     }
 
-    boolean areBackgroundActivityStartsAllowed() {
-        // allow if any activity in the caller has either started or finished very recently, and
-        // it must be started or finished after last stop app switches time.
-        final long now = SystemClock.uptimeMillis();
-        if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
-                || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
-            // if activity is started and finished before stop app switch time, we should not
-            // let app to be able to start background activity even it's in grace period.
-            if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime()
-                    || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "[WindowProcessController(" + mPid
-                            + ")] Activity start allowed: within "
-                            + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
+    boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
+        // If app switching is not allowed, we ignore all the start activity grace period
+        // exception so apps cannot start itself in onPause() after pressing home button.
+        if (appSwitchAllowed) {
+            // allow if any activity in the caller has either started or finished very recently, and
+            // it must be started or finished after last stop app switches time.
+            final long now = SystemClock.uptimeMillis();
+            if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
+                    || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
+                // if activity is started and finished before stop app switch time, we should not
+                // let app to be able to start background activity even it's in grace period.
+                if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime()
+                        || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) {
+                    if (DEBUG_ACTIVITY_STARTS) {
+                        Slog.d(TAG, "[WindowProcessController(" + mPid
+                                + ")] Activity start allowed: within "
+                                + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
+                    }
+                    return true;
                 }
-                return true;
-            }
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within "
-                        + ACTIVITY_BG_START_GRACE_PERIOD_MS
-                        + "ms grace period but also within stop app switch window");
-            }
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within "
+                            + ACTIVITY_BG_START_GRACE_PERIOD_MS
+                            + "ms grace period but also within stop app switch window");
+                }
 
+            }
         }
         // allow if the proc is instrumenting with background activity starts privs
         if (mInstrumentingWithBackgroundActivityStartPrivileges) {
@@ -549,7 +554,7 @@
             return true;
         }
         // allow if the caller has an activity in any foreground task
-        if (hasActivityInVisibleTask()) {
+        if (appSwitchAllowed && hasActivityInVisibleTask()) {
             if (DEBUG_ACTIVITY_STARTS) {
                 Slog.d(TAG, "[WindowProcessController(" + mPid
                         + ")] Activity start allowed: process has activity in foreground task");
@@ -892,16 +897,9 @@
     }
 
     boolean hasResumedActivity() {
-        for (int i = mActivities.size() - 1; i >= 0; --i) {
-            final ActivityRecord activity = mActivities.get(i);
-            if (activity.isState(RESUMED)) {
-                return true;
-            }
-        }
-        return false;
+        return (mActivityStateFlags & ACTIVITY_STATE_FLAG_HAS_RESUMED) != 0;
     }
 
-
     void updateIntentForHeavyWeightActivity(Intent intent) {
         if (mActivities.isEmpty()) {
             return;
@@ -1041,10 +1039,14 @@
         // Since there could be more than one activities in a process record, we don't need to
         // compute the OomAdj with each of them, just need to find out the activity with the
         // "best" state, the order would be visible, pausing, stopping...
-        Task.ActivityState best = DESTROYED;
-        boolean finishing = true;
+        Task.ActivityState bestInvisibleState = DESTROYED;
+        boolean allStoppingFinishing = true;
         boolean visible = false;
         int minTaskLayer = Integer.MAX_VALUE;
+        int stateFlags = 0;
+        final boolean wasResumed = hasResumedActivity();
+        final boolean wasAnyVisible = (mActivityStateFlags
+                & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
             if (r.app != this) {
@@ -1057,7 +1059,13 @@
                     continue;
                 }
             }
+            if (r.isVisible()) {
+                stateFlags |= ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE;
+            }
             if (r.mVisibleRequested) {
+                if (r.isState(RESUMED)) {
+                    stateFlags |= ACTIVITY_STATE_FLAG_HAS_RESUMED;
+                }
                 final Task task = r.getTask();
                 if (task != null && minTaskLayer > 0) {
                     final int layer = task.mLayerRank;
@@ -1069,29 +1077,39 @@
                 // continue the loop, in case there are multiple visible activities in
                 // this process, we'd find out the one with the minimal layer, thus it'll
                 // get a higher adj score.
-            } else if (best != PAUSING && best != PAUSED) {
+            } else if (!visible && bestInvisibleState != PAUSING) {
                 if (r.isState(PAUSING, PAUSED)) {
-                    best = PAUSING;
+                    bestInvisibleState = PAUSING;
                 } else if (r.isState(STOPPING)) {
-                    best = STOPPING;
+                    bestInvisibleState = STOPPING;
                     // Not "finishing" if any of activity isn't finishing.
-                    finishing &= r.finishing;
+                    allStoppingFinishing &= r.finishing;
                 }
             }
         }
 
-        int stateFlags = minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
+        stateFlags |= minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
         if (visible) {
             stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
-        } else if (best == PAUSING) {
+        } else if (bestInvisibleState == PAUSING) {
             stateFlags |= ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
-        } else if (best == STOPPING) {
+        } else if (bestInvisibleState == STOPPING) {
             stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING;
-            if (finishing) {
+            if (allStoppingFinishing) {
                 stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
             }
         }
         mActivityStateFlags = stateFlags;
+
+        final boolean anyVisible = (stateFlags
+                & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
+        if (!wasAnyVisible && anyVisible) {
+            mAtm.mVisibleActivityProcessTracker.onAnyActivityVisible(this);
+        } else if (wasAnyVisible && !anyVisible) {
+            mAtm.mVisibleActivityProcessTracker.onAllActivitiesInvisible(this);
+        } else if (wasAnyVisible && !wasResumed && hasResumedActivity()) {
+            mAtm.mVisibleActivityProcessTracker.onActivityResumedWhileVisible(this);
+        }
     }
 
     /** Called when the process has some oom related changes and it is going to update oom-adj. */
@@ -1643,6 +1661,32 @@
         pw.println(prefix + " Configuration=" + getConfiguration());
         pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
         pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
+
+        final int stateFlags = mActivityStateFlags;
+        if (stateFlags != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
+            pw.print(prefix + " mActivityStateFlags=");
+            if ((stateFlags & ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE) != 0) {
+                pw.print("W|");
+            }
+            if ((stateFlags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0) {
+                pw.print("V|");
+                if ((stateFlags & ACTIVITY_STATE_FLAG_HAS_RESUMED) != 0) {
+                    pw.print("R|");
+                }
+            } else if ((stateFlags & ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED) != 0) {
+                pw.print("P|");
+            } else if ((stateFlags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) {
+                pw.print("S|");
+                if ((stateFlags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0) {
+                    pw.print("F|");
+                }
+            }
+            final int taskLayer = stateFlags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
+            if (taskLayer != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
+                pw.print("taskLayer=" + taskLayer);
+            }
+            pw.println();
+        }
     }
 
     void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5ab4ba1..64d24fb 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -694,6 +694,8 @@
     private @Nullable InsetsSourceProvider mControllableInsetProvider;
     private final InsetsState mRequestedInsetsState = new InsetsState();
 
+    @Nullable InsetsSourceProvider mPendingPositionChanged;
+
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
     private KeyInterceptionInfo mKeyInterceptionInfo;
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e9d048a..3bff440 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -3514,10 +3514,11 @@
     return gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
 }
 
-static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
-        JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
+static jboolean android_location_GnssConfiguration_set_satellite_blocklist(JNIEnv* env, jobject,
+                                                                           jintArray constellations,
+                                                                           jintArray sv_ids) {
     if (gnssConfigurationIface == nullptr) {
-        ALOGI("IGnssConfiguration interface does not support satellite blacklist.");
+        ALOGI("IGnssConfiguration interface does not support satellite blocklist.");
         return JNI_FALSE;
     }
     return gnssConfigurationIface->setBlocklist(env, constellations, sv_ids);
@@ -3532,7 +3533,7 @@
     return gnssConfigurationIface->setEsExtensionSec(emergencyExtensionSeconds);
 }
 
-static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
+static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return 0; // batching not supported, size = 0
     }
@@ -3544,7 +3545,7 @@
     return static_cast<jint>(result);
 }
 
-static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
+static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
     if (gnssBatchingIface_V2_0 != nullptr) {
         sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
         auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0);
@@ -3558,7 +3559,7 @@
     }
 }
 
-static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jclass) {
+static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return; // batching not supported
     }
@@ -3566,8 +3567,9 @@
     checkHidlReturn(result, "IGnssBatching cleanup() failed.");
 }
 
-static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass,
-        jlong periodNanos, jboolean wakeOnFifoFull) {
+static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
+                                                                  jlong periodNanos,
+                                                                  jboolean wakeOnFifoFull) {
     if (gnssBatchingIface == nullptr) {
         return JNI_FALSE; // batching not supported
     }
@@ -3584,7 +3586,7 @@
     return checkHidlReturn(result, "IGnssBatching start() failed.");
 }
 
-static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
+static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return; // batching not supported
     }
@@ -3592,7 +3594,7 @@
     checkHidlReturn(result, "IGnssBatching flush() failed.");
 }
 
-static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) {
+static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return JNI_FALSE; // batching not supported
     }
@@ -3670,25 +3672,19 @@
 };
 
 static const JNINativeMethod sMethodsBatching[] = {
-     /* name, signature, funcPtr */
-    {"native_get_batch_size",
-            "()I",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_get_batch_size)},
-    {"native_start_batch",
-            "(JZ)Z",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_start_batch)},
-    {"native_flush_batch",
-            "()V",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_flush_batch)},
-    {"native_stop_batch",
-            "()Z",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_stop_batch)},
-    {"native_init_batching",
-            "()Z",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_init_batching)},
-    {"native_cleanup_batching",
-            "()V",
-            reinterpret_cast<void *>(android_location_GnssBatchingProvider_cleanup_batching)},
+        /* name, signature, funcPtr */
+        {"native_get_batch_size", "()I",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_get_batch_size)},
+        {"native_start_batch", "(JZ)Z",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_start_batch)},
+        {"native_flush_batch", "()V",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_flush_batch)},
+        {"native_stop_batch", "()Z",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_stop_batch)},
+        {"native_init_batching", "()Z",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_init_batching)},
+        {"native_cleanup_batching", "()V",
+         reinterpret_cast<void*>(android_location_GnssLocationProvider_cleanup_batching)},
 };
 
 static const JNINativeMethod sAntennaInfoMethods[] = {
@@ -3800,8 +3796,8 @@
          reinterpret_cast<void*>(android_location_GnssConfiguration_set_gps_lock)},
         {"native_set_emergency_supl_pdn", "(I)Z",
          reinterpret_cast<void*>(android_location_GnssConfiguration_set_emergency_supl_pdn)},
-        {"native_set_satellite_blacklist", "([I[I)Z",
-         reinterpret_cast<void*>(android_location_GnssConfiguration_set_satellite_blacklist)},
+        {"native_set_satellite_blocklist", "([I[I)Z",
+         reinterpret_cast<void*>(android_location_GnssConfiguration_set_satellite_blocklist)},
         {"native_set_es_extension_sec", "(I)Z",
          reinterpret_cast<void*>(android_location_GnssConfiguration_set_es_extension_sec)},
 };
@@ -3817,7 +3813,7 @@
 int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
     jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider",
                              sAntennaInfoMethods, NELEM(sAntennaInfoMethods));
-    jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssBatchingProvider",
+    jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider",
                              sMethodsBatching, NELEM(sMethodsBatching));
     jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider",
                              sGeofenceMethods, NELEM(sGeofenceMethods));
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 767496d..2190392 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3738,11 +3738,11 @@
         Objects.requireNonNull(admin, "ComponentName is null");
 
         final CallerIdentity caller = getCallerIdentity(admin);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
         List<String> changedProviders = null;
 
         synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
             if (activeAdmin.crossProfileWidgetProviders == null) {
                 activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
             }
@@ -3773,11 +3773,11 @@
         Objects.requireNonNull(admin, "ComponentName is null");
 
         final CallerIdentity caller = getCallerIdentity(admin);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
         List<String> changedProviders = null;
 
         synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
             if (activeAdmin.crossProfileWidgetProviders == null
                     || activeAdmin.crossProfileWidgetProviders.isEmpty()) {
                 return false;
@@ -3808,10 +3808,10 @@
         Objects.requireNonNull(admin, "ComponentName is null");
 
         final CallerIdentity caller = getCallerIdentity(admin);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
 
         synchronized (getLockObject()) {
-            ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
             if (activeAdmin.crossProfileWidgetProviders == null
                     || activeAdmin.crossProfileWidgetProviders.isEmpty()) {
                 return null;
@@ -9184,7 +9184,7 @@
         }
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin admin = getProfileOwnerLocked(caller);
             admin.permittedNotificationListeners = packageList;
             saveSettingsLocked(caller.getUserId());
         }
@@ -10160,10 +10160,10 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin admin = getProfileOwnerLocked(caller);
             if (admin.disableCallerId != disabled) {
                 admin.disableCallerId = disabled;
                 saveSettingsLocked(caller.getUserId());
@@ -10183,10 +10183,10 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin admin = getProfileOwnerLocked(caller);
             return admin.disableCallerId;
         }
     }
@@ -10211,10 +10211,10 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin admin = getProfileOwnerLocked(caller);
             if (admin.disableContactsSearch != disabled) {
                 admin.disableContactsSearch = disabled;
                 saveSettingsLocked(caller.getUserId());
@@ -10234,10 +10234,10 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        Preconditions.checkCallAuthorization(isProfileOwner(caller));
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            ActiveAdmin admin = getProfileOwnerLocked(caller);
             return admin.disableContactsSearch;
         }
     }
@@ -14358,7 +14358,7 @@
         final CallerIdentity caller = getCallerIdentity(who);
 
         synchronized (getLockObject()) {
-            final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            final ActiveAdmin admin = getProfileOwnerLocked(caller);
             admin.mCrossProfileCalendarPackages = packageNames;
             saveSettingsLocked(caller.getUserId());
         }
@@ -14379,7 +14379,7 @@
         final CallerIdentity caller = getCallerIdentity(who);
 
         synchronized (getLockObject()) {
-            final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            final ActiveAdmin admin = getProfileOwnerLocked(caller);
             return admin.mCrossProfileCalendarPackages;
         }
     }
@@ -14442,7 +14442,7 @@
 
         final List<String> previousCrossProfilePackages;
         synchronized (getLockObject()) {
-            final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            final ActiveAdmin admin = getProfileOwnerLocked(caller);
             previousCrossProfilePackages = admin.mCrossProfilePackages;
             if (packageNames.equals(previousCrossProfilePackages)) {
                 return;
@@ -14474,7 +14474,7 @@
         final CallerIdentity caller = getCallerIdentity(who);
 
         synchronized (getLockObject()) {
-            final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+            final ActiveAdmin admin = getProfileOwnerLocked(caller);
             return admin.mCrossProfilePackages;
         }
     }
diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index c03a5a7..e4daddc 100644
--- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
+++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
@@ -185,22 +185,23 @@
      * is useful for when device is powering off.
      */
     @MainThread
-    synchronized void saveImmediately(@NonNull String fileName, @NonNull T data) {
-        mScheduledFileDataMap.put(fileName, data);
+    void saveImmediately(@NonNull String fileName, @NonNull T data) {
+        synchronized (this) {
+            mScheduledFileDataMap.put(fileName, data);
+        }
         triggerScheduledFlushEarly();
     }
 
     @MainThread
-    private synchronized void triggerScheduledFlushEarly() {
-        if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
-            return;
-        }
-        // Cancel existing future.
-        if (mScheduledFuture != null) {
-
-            // We shouldn't need to interrupt as this method and threaded task
-            // #flushScheduledData are both synchronized.
-            mScheduledFuture.cancel(true);
+    private void triggerScheduledFlushEarly() {
+        synchronized (this) {
+            if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
+                return;
+            }
+            // Cancel existing future.
+            if (mScheduledFuture != null) {
+                mScheduledFuture.cancel(true);
+            }
         }
 
         // Submit flush and blocks until it completes. Blocking will prevent the device from
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
deleted file mode 100644
index fa324e8..0000000
--- a/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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.location.gnss;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.location.gnss.GnssBatchingProvider.GnssBatchingProviderNative;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-/**
- * Unit tests for {@link GnssBatchingProvider}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class GnssBatchingProviderTest {
-
-    private static final long PERIOD_NANOS = (long) 1e9;
-    private static final boolean WAKE_ON_FIFO_FULL = true;
-    private static final int BATCH_SIZE = 3;
-    @Mock
-    private GnssBatchingProviderNative mMockNative;
-    private GnssBatchingProvider mTestProvider;
-
-    /**
-     * Mocks native methods and starts GnssBatchingProvider.
-     */
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mMockNative.initBatching()).thenReturn(true);
-        when(mMockNative.startBatch(anyLong(), anyBoolean())).thenReturn(true);
-        when(mMockNative.stopBatch()).thenReturn(true);
-        when(mMockNative.getBatchSize()).thenReturn(BATCH_SIZE);
-        mTestProvider = new GnssBatchingProvider(mMockNative);
-        mTestProvider.enable();
-        mTestProvider.start(PERIOD_NANOS, WAKE_ON_FIFO_FULL);
-    }
-
-    /**
-     * Test native start method is called.
-     */
-    @Test
-    public void start_nativeStarted() {
-        verify(mMockNative).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
-    }
-
-    /**
-     * Verify native stop method is called.
-     */
-    @Test
-    public void stop_nativeStopped() {
-        mTestProvider.stop();
-        verify(mMockNative).stopBatch();
-    }
-
-    /**
-     * Verify native flush method is called.
-     */
-    @Test
-    public void flush_nativeFlushed() {
-        mTestProvider.flush();
-        verify(mMockNative).flushBatch();
-    }
-
-    /**
-     * Verify getBatchSize returns value from native batch size method.
-     */
-    @Test
-    public void getBatchSize_nativeGetBatchSize() {
-        assertThat(mTestProvider.getBatchSize()).isEqualTo(BATCH_SIZE);
-    }
-
-    /**
-     * Verify resumeIfStarted method will call native start method a second time.
-     */
-    @Test
-    public void started_resume_started() {
-        mTestProvider.resumeIfStarted();
-        verify(mMockNative, times(2)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
-    }
-
-    /**
-     * Verify that if batching is stopped, resume will not call native start method.
-     */
-    @Test
-    public void stopped_resume_notStarted() {
-        mTestProvider.stop();
-        mTestProvider.resumeIfStarted();
-        verify(mMockNative, times(1)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
-    }
-}
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java
similarity index 60%
rename from services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java
rename to services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java
index ce89b9b..910a6f5 100644
--- a/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java
@@ -43,101 +43,101 @@
 import java.util.List;
 
 /**
- * Unit tests for {@link GnssSatelliteBlacklistHelper}.
+ * Unit tests for {@link GnssSatelliteBlocklistHelper}.
  */
 @RunWith(RobolectricTestRunner.class)
 @Presubmit
-public class GnssSatelliteBlacklistHelperTest {
+public class GnssSatelliteBlocklistHelperTest {
 
     private ContentResolver mContentResolver;
     @Mock
-    private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback;
+    private GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback mCallback;
 
     /**
-     * Initialize mocks and create GnssSatelliteBlacklistHelper with callback.
+     * Initialize mocks and create GnssSatelliteBlocklistHelper with callback.
      */
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         Context context = RuntimeEnvironment.application;
         mContentResolver = context.getContentResolver();
-        new GnssSatelliteBlacklistHelper(context, Looper.myLooper(), mCallback);
+        new GnssSatelliteBlocklistHelper(context, Looper.myLooper(), mCallback);
     }
 
     /**
-     * Blacklist two satellites and verify callback is called.
+     * Blocklist two satellites and verify callback is called.
      */
     @Test
-    public void blacklistOf2Satellites_callbackIsCalled() {
-        String blacklist = "3,0,5,24";
-        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    public void blocklistOf2Satellites_callbackIsCalled() {
+        String blocklist = "3,0,5,24";
+        updateBlocklistAndVerifyCallbackIsCalled(blocklist);
     }
 
     /**
-     * Blacklist one satellite with spaces in string and verify callback is called.
+     * Blocklist one satellite with spaces in string and verify callback is called.
      */
     @Test
-    public void blacklistWithSpaces_callbackIsCalled() {
-        String blacklist = "3, 11";
-        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    public void blocklistWithSpaces_callbackIsCalled() {
+        String blocklist = "3, 11";
+        updateBlocklistAndVerifyCallbackIsCalled(blocklist);
     }
 
     /**
-     * Pass empty blacklist and verify callback is called.
+     * Pass empty blocklist and verify callback is called.
      */
     @Test
-    public void emptyBlacklist_callbackIsCalled() {
-        String blacklist = "";
-        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    public void emptyBlocklist_callbackIsCalled() {
+        String blocklist = "";
+        updateBlocklistAndVerifyCallbackIsCalled(blocklist);
     }
 
     /**
-     * Pass blacklist string with odd number of values and verify callback is not called.
+     * Pass blocklist string with odd number of values and verify callback is not called.
      */
     @Test
-    public void blacklistWithOddNumberOfValues_callbackIsNotCalled() {
-        String blacklist = "3,0,5";
-        updateBlacklistAndNotifyContentObserver(blacklist);
-        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    public void blocklistWithOddNumberOfValues_callbackIsNotCalled() {
+        String blocklist = "3,0,5";
+        updateBlocklistAndNotifyContentObserver(blocklist);
+        verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
     }
 
     /**
-     * Pass blacklist string with negative value and verify callback is not called.
+     * Pass blocklist string with negative value and verify callback is not called.
      */
     @Test
-    public void blacklistWithNegativeValue_callbackIsNotCalled() {
-        String blacklist = "3,-11";
-        updateBlacklistAndNotifyContentObserver(blacklist);
-        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    public void blocklistWithNegativeValue_callbackIsNotCalled() {
+        String blocklist = "3,-11";
+        updateBlocklistAndNotifyContentObserver(blocklist);
+        verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
     }
 
     /**
-     * Pass blacklist string with non-digit characters and verify callback is not called.
+     * Pass blocklist string with non-digit characters and verify callback is not called.
      */
     @Test
-    public void blacklistWithNonDigitCharacter_callbackIsNotCalled() {
-        String blacklist = "3,1a,5,11";
-        updateBlacklistAndNotifyContentObserver(blacklist);
-        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    public void blocklistWithNonDigitCharacter_callbackIsNotCalled() {
+        String blocklist = "3,1a,5,11";
+        updateBlocklistAndNotifyContentObserver(blocklist);
+        verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
     }
 
-    private void updateBlacklistAndNotifyContentObserver(String blacklist) {
+    private void updateBlocklistAndNotifyContentObserver(String blocklist) {
         Settings.Global.putString(mContentResolver,
-                Settings.Global.GNSS_SATELLITE_BLACKLIST, blacklist);
-        notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLACKLIST);
+                Settings.Global.GNSS_SATELLITE_BLOCKLIST, blocklist);
+        notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLOCKLIST);
     }
 
-    private void updateBlacklistAndVerifyCallbackIsCalled(String blacklist) {
-        updateBlacklistAndNotifyContentObserver(blacklist);
+    private void updateBlocklistAndVerifyCallbackIsCalled(String blocklist) {
+        updateBlocklistAndNotifyContentObserver(blocklist);
 
         ArgumentCaptor<int[]> constellationsCaptor = ArgumentCaptor.forClass(int[].class);
         ArgumentCaptor<int[]> svIdsCaptor = ArgumentCaptor.forClass(int[].class);
-        verify(mCallback).onUpdateSatelliteBlacklist(constellationsCaptor.capture(),
+        verify(mCallback).onUpdateSatelliteBlocklist(constellationsCaptor.capture(),
                 svIdsCaptor.capture());
 
         int[] constellations = constellationsCaptor.getValue();
         int[] svIds = svIdsCaptor.getValue();
-        List<Integer> values = GnssSatelliteBlacklistHelper.parseSatelliteBlacklist(blacklist);
+        List<Integer> values = GnssSatelliteBlocklistHelper.parseSatelliteBlocklist(blocklist);
         assertThat(values.size()).isEqualTo(constellations.length * 2);
         assertThat(svIds.length).isEqualTo(constellations.length);
         for (int i = 0; i < constellations.length; i++) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 6a6fb82..dbdee979 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -42,6 +42,8 @@
 import com.android.server.LocalServices;
 import com.android.server.lights.LightsManager;
 
+import com.google.common.truth.Truth;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -190,6 +192,102 @@
                 16000);
     }
 
+    private static class DisplayModeWrapper {
+        public SurfaceControl.DisplayConfig config;
+        public float[] expectedAlternativeRefreshRates;
+
+        DisplayModeWrapper(SurfaceControl.DisplayConfig config,
+                float[] expectedAlternativeRefreshRates) {
+            this.config = config;
+            this.expectedAlternativeRefreshRates = expectedAlternativeRefreshRates;
+        }
+    }
+
+    /**
+     * Updates the <code>display</code> using the given <code>modes</code> and then checks if the
+     * <code>expectedAlternativeRefreshRates</code> are present for each of the
+     * <code>modes</code>.
+     */
+    private void testAlternativeRefreshRatesCommon(FakeDisplay display, DisplayModeWrapper[] modes)
+            throws InterruptedException {
+        // Update the display.
+        SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[modes.length];
+        for (int i = 0; i < modes.length; i++) {
+            configs[i] = modes[i].config;
+        }
+        display.configs = configs;
+        setUpDisplay(display);
+        mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        assertThat(mListener.changedDisplays.size()).isGreaterThan(0);
+
+        // Verify the supported modes are updated accordingly.
+        DisplayDevice displayDevice =
+                mListener.changedDisplays.get(mListener.changedDisplays.size() - 1);
+        displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+        Display.Mode[] supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
+        assertThat(supportedModes.length).isEqualTo(configs.length);
+
+        for (int i = 0; i < modes.length; i++) {
+            assertModeIsSupported(supportedModes, configs[i],
+                    modes[i].expectedAlternativeRefreshRates);
+        }
+    }
+
+    @Test
+    public void testAfterDisplayChange_AlternativeRefreshRatesAreUpdated() throws Exception {
+        FakeDisplay display = new FakeDisplay(PORT_A);
+        setUpDisplay(display);
+        updateAvailableDisplays();
+        mAdapter.registerLocked();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+        testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{24f, 50f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{24f, 60f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 24f, 0), new float[]{50f, 60f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 60f, 0), new float[]{24f, 50f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 50f, 0), new float[]{24f, 60f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 24f, 0), new float[]{50f, 60f}),
+        });
+
+        testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{50f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{60f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 24f, 1), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 60f, 2), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 50f, 3), new float[]{24f}),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 24f, 3), new float[]{50f}),
+        });
+
+        testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 60f, 0), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 50f, 1), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(1920, 1080, 24f, 2), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 60f, 3), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 50f, 4), new float[0]),
+                new DisplayModeWrapper(
+                        createFakeDisplayConfig(3840, 2160, 24f, 5), new float[0]),
+        });
+    }
+
     @Test
     public void testAfterDisplayChange_DisplayModesAreUpdated() throws Exception {
         SurfaceControl.DisplayConfig displayConfig = createFakeDisplayConfig(1920, 1080, 60f);
@@ -419,6 +517,23 @@
                 x -> x.matches(mode.width, mode.height, mode.refreshRate))).isTrue();
     }
 
+    private void assertModeIsSupported(Display.Mode[] supportedModes,
+            SurfaceControl.DisplayConfig mode, float[] alternativeRefreshRates) {
+        float[] sortedAlternativeRates =
+                Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
+        Arrays.sort(sortedAlternativeRates);
+
+        String message = "Expected " + mode + " with alternativeRefreshRates = "
+                + Arrays.toString(alternativeRefreshRates) + " to be in list of supported modes = "
+                + Arrays.toString(supportedModes);
+        Truth.assertWithMessage(message)
+            .that(Arrays.stream(supportedModes)
+                .anyMatch(x -> x.matches(mode.width, mode.height, mode.refreshRate)
+                        && Arrays.equals(x.getAlternativeRefreshRates(), sortedAlternativeRates)))
+                .isTrue();
+    }
+
+
     private static class FakeDisplay {
         public final DisplayAddress.Physical address;
         public final IBinder token = new Binder();
@@ -492,12 +607,18 @@
 
     private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
             float refreshRate) {
+        return createFakeDisplayConfig(width, height, refreshRate, 0);
+    }
+
+    private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
+            float refreshRate, int configGroup) {
         final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig();
         config.width = width;
         config.height = height;
         config.refreshRate = refreshRate;
         config.xDpi = 100;
         config.yDpi = 100;
+        config.configGroup = configGroup;
         return config;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 7954208..77fef12 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1430,8 +1430,8 @@
                 createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
-        mQuotaController.incrementJobCount(0, "com.android.test", 5);
         synchronized (mQuotaController.mLock) {
+            mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
             assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
         }
     }
@@ -1445,8 +1445,8 @@
                 createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
         mQuotaController.saveTimingSession(0, "com.android.test.spam",
                 createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
-        mQuotaController.incrementJobCount(0, "com.android.test.spam", jobCount);
         synchronized (mQuotaController.mLock) {
+            mQuotaController.incrementJobCountLocked(0, "com.android.test.spam", jobCount);
             assertFalse(mQuotaController.isWithinQuotaLocked(
                     0, "com.android.test.spam", WORKING_INDEX));
         }
@@ -1471,8 +1471,8 @@
                 createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5));
-        mQuotaController.incrementJobCount(0, "com.android.test", 5);
         synchronized (mQuotaController.mLock) {
+            mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
             assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
         }
     }
@@ -1486,8 +1486,8 @@
                 createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
-        mQuotaController.incrementJobCount(0, "com.android.test", jobCount);
         synchronized (mQuotaController.mLock) {
+            mQuotaController.incrementJobCountLocked(0, "com.android.test", jobCount);
             assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
         }
     }
@@ -1637,9 +1637,10 @@
             mQuotaController.saveTimingSession(0, "com.android.test",
                     createTimingSession(now - ((10 - i) * MINUTE_IN_MILLIS), 30 * SECOND_IN_MILLIS,
                             2));
-            mQuotaController.incrementJobCount(0, "com.android.test", 2);
 
             synchronized (mQuotaController.mLock) {
+                mQuotaController.incrementJobCountLocked(0, "com.android.test", 2);
+
                 assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions",
                         i < 2,
                         mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX));
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index d260e4d..b55da07 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -31,6 +31,7 @@
 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
 import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
 import static com.android.server.location.LocationUtils.createLocation;
+import static com.android.server.location.LocationUtils.createLocationResult;
 import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -40,10 +41,12 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -52,6 +55,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.MockitoAnnotations.initMocks;
+import static org.testng.Assert.assertThrows;
 
 import android.content.Context;
 import android.location.ILocationCallback;
@@ -60,6 +64,7 @@
 import android.location.LocationManagerInternal;
 import android.location.LocationManagerInternal.ProviderEnabledListener;
 import android.location.LocationRequest;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.os.Bundle;
 import android.os.ICancellationSignal;
@@ -85,11 +90,12 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
@@ -152,7 +158,7 @@
 
         mPassive = new PassiveLocationProviderManager(mContext, mInjector);
         mPassive.startManager();
-        mPassive.setRealProvider(new PassiveProvider(mContext));
+        mPassive.setRealProvider(new PassiveLocationProvider(mContext));
 
         mProvider = new TestProvider(PROPERTIES, IDENTITY);
         mProvider.setProviderAllowed(true);
@@ -308,7 +314,7 @@
 
     @Test
     public void testGetLastLocation_ClearOnMockRemoval() {
-        MockProvider mockProvider = new MockProvider(PROPERTIES, IDENTITY);
+        MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, IDENTITY);
         mockProvider.setAllowed(true);
         mManager.setMockProvider(mockProvider);
 
@@ -339,13 +345,9 @@
         LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
         mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
 
-        Location loc = createLocation(NAME, mRandom);
+        LocationResult loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-
-        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-        verify(listener).onLocationChanged(locationCaptor.capture(),
-                nullable(IRemoteCallback.class));
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+        verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
     }
 
     @Test
@@ -358,8 +360,6 @@
 
     @Test
     public void testRegisterListener() throws Exception {
-        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
         ILocationListener listener = createMockLocationListener();
         mManager.registerLocationRequest(
                 new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
@@ -367,17 +367,15 @@
                 PERMISSION_FINE,
                 listener);
 
-        Location loc = createLocation(NAME, mRandom);
+        LocationResult loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        verify(listener, times(1)).onLocationChanged(locationCaptor.capture(),
-                nullable(IRemoteCallback.class));
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+        verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
 
         mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
         verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
-        loc = createLocation(NAME, mRandom);
+        loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        verify(listener, times(1)).onLocationChanged(any(Location.class),
+        verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
 
         mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
@@ -385,25 +383,21 @@
 
         mProvider.setAllowed(false);
         verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
-        loc = createLocation(NAME, mRandom);
+        loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        verify(listener, times(1)).onLocationChanged(any(Location.class),
+        verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
 
         mProvider.setAllowed(true);
         verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, true);
 
-        loc = createLocation(NAME, mRandom);
+        loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        verify(listener, times(2)).onLocationChanged(locationCaptor.capture(),
-                nullable(IRemoteCallback.class));
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+        verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
     }
 
     @Test
     public void testRegisterListener_SameProcess() throws Exception {
-        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
         CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
                 "attribution");
 
@@ -414,11 +408,10 @@
                 PERMISSION_FINE,
                 listener);
 
-        Location loc = createLocation(NAME, mRandom);
+        LocationResult loc = createLocationResult(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(locationCaptor.capture(),
+        verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(eq(loc),
                 nullable(IRemoteCallback.class));
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
     }
 
     @Test
@@ -432,7 +425,7 @@
         mManager.unregisterLocationRequest(listener);
 
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
-        verify(listener, never()).onLocationChanged(any(Location.class),
+        verify(listener, never()).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
 
         mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
@@ -463,7 +456,7 @@
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         mManager.unregisterLocationRequest(listener);
         blocker.countDown();
-        verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(Location.class),
+        verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
     }
 
@@ -483,7 +476,7 @@
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
 
-        verify(listener, times(5)).onLocationChanged(any(Location.class),
+        verify(listener, times(5)).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
     }
 
@@ -498,7 +491,7 @@
 
         mInjector.getAlarmHelper().incrementAlarmTime(5000);
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
-        verify(listener, never()).onLocationChanged(any(Location.class),
+        verify(listener, never()).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
     }
 
@@ -514,7 +507,7 @@
         Thread.sleep(25);
 
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
-        verify(listener, never()).onLocationChanged(any(Location.class),
+        verify(listener, never()).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
     }
 
@@ -530,8 +523,8 @@
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
 
-        verify(listener, times(1)).onLocationChanged(any(Location.class),
-                nullable(IRemoteCallback.class));
+        verify(listener, times(1)).onLocationChanged(
+                any(LocationResult.class), nullable(IRemoteCallback.class));
     }
 
     @Test
@@ -547,8 +540,8 @@
         mProvider.setProviderLocation(loc);
         mProvider.setProviderLocation(loc);
 
-        verify(listener, times(1)).onLocationChanged(any(Location.class),
-                nullable(IRemoteCallback.class));
+        verify(listener, times(1)).onLocationChanged(
+                any(LocationResult.class), nullable(IRemoteCallback.class));
     }
 
     @Test
@@ -562,7 +555,7 @@
 
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
 
-        verify(listener, never()).onLocationChanged(any(Location.class),
+        verify(listener, never()).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
     }
 
@@ -592,7 +585,7 @@
         verify(mWakeLock, never()).release();
 
         blocker.countDown();
-        verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(Location.class),
+        verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(LocationResult.class),
                 nullable(IRemoteCallback.class));
         verify(mWakeLock).acquire(anyLong());
         verify(mWakeLock, timeout(TIMEOUT_MS)).release();
@@ -610,7 +603,7 @@
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         verify(listener, times(1))
-                .onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+                .onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
     }
 
     @Test
@@ -627,13 +620,11 @@
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
         verify(listener, times(1))
-                .onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+                .onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
     }
 
     @Test
     public void testGetCurrentLocation() throws Exception {
-        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
         ILocationCallback listener = createMockGetCurrentLocationListener();
         LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
         mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
@@ -641,9 +632,7 @@
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
-
-        verify(listener, times(1)).onLocation(locationCaptor.capture());
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+        verify(listener, times(1)).onLocation(loc);
     }
 
     @Test
@@ -655,7 +644,6 @@
 
         cancellationSignal.cancel();
         mProvider.setProviderLocation(createLocation(NAME, mRandom));
-
         verify(listener, never()).onLocation(nullable(Location.class));
     }
 
@@ -686,17 +674,13 @@
 
     @Test
     public void testGetCurrentLocation_LastLocation() throws Exception {
-        ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
 
         ILocationCallback listener = createMockGetCurrentLocationListener();
         LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
         mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
-
-        verify(listener, times(1)).onLocation(locationCaptor.capture());
-        assertThat(locationCaptor.getValue()).isEqualTo(loc);
+        verify(listener, times(1)).onLocation(eq(loc));
     }
 
     @Test
@@ -710,6 +694,32 @@
     }
 
     @Test
+    public void testFlush() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        mManager.registerLocationRequest(
+                new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
+                IDENTITY,
+                PERMISSION_FINE,
+                listener);
+
+        mManager.flush(listener, 99);
+
+        LocationResult loc = createLocationResult(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        mProvider.completeFlushes();
+
+        InOrder inOrder = inOrder(listener);
+        inOrder.verify(listener).onLocationChanged(eq(loc), any(IRemoteCallback.class));
+        inOrder.verify(listener).onFlushComplete(99);
+    }
+
+    @Test
+    public void testFlush_UnknownKey() {
+        assertThrows(IllegalArgumentException.class,
+                () -> mManager.flush(createMockLocationListener(), 0));
+    }
+
+    @Test
     public void testLocationMonitoring() {
         assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
                 IDENTITY.getPackageName())).isFalse();
@@ -791,7 +801,8 @@
                 .build();
         mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
 
-        verify(listener1).onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+        verify(listener1).onLocationChanged(any(LocationResult.class),
+                nullable(IRemoteCallback.class));
 
         assertThat(mProvider.getRequest().isActive()).isFalse();
 
@@ -941,7 +952,8 @@
     private ILocationListener createMockLocationListener() {
         return spy(new ILocationListener.Stub() {
             @Override
-            public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
+            public void onLocationChanged(LocationResult location,
+                    IRemoteCallback onCompleteCallback) {
                 if (onCompleteCallback != null) {
                     try {
                         onCompleteCallback.sendResult(null);
@@ -952,6 +964,10 @@
             }
 
             @Override
+            public void onFlushComplete(int requestCode) {
+            }
+
+            @Override
             public void onProviderEnabledChanged(String provider, boolean enabled) {
             }
         });
@@ -969,6 +985,8 @@
 
         private ProviderRequest mProviderRequest = ProviderRequest.EMPTY_REQUEST;
 
+        private final ArrayList<Runnable> mFlushCallbacks = new ArrayList<>();
+
         TestProvider(ProviderProperties properties, CallerIdentity identity) {
             super(DIRECT_EXECUTOR, identity);
             setProperties(properties);
@@ -979,7 +997,18 @@
         }
 
         public void setProviderLocation(Location l) {
-            reportLocation(new Location(l));
+            reportLocation(LocationResult.create(new Location(l)));
+        }
+
+        public void setProviderLocation(LocationResult l) {
+            reportLocation(l);
+        }
+
+        public void completeFlushes() {
+            for (Runnable r : mFlushCallbacks) {
+                r.run();
+            }
+            mFlushCallbacks.clear();
         }
 
         public ProviderRequest getRequest() {
@@ -992,6 +1021,11 @@
         }
 
         @Override
+        protected void onFlush(Runnable callback) {
+            mFlushCallbacks.add(callback);
+        }
+
+        @Override
         protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
         }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
index decb3a6..593e62a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
@@ -17,8 +17,10 @@
 package com.android.server.location;
 
 import android.location.Location;
+import android.location.LocationResult;
 import android.os.SystemClock;
 
+import java.util.Arrays;
 import java.util.Random;
 
 public final class LocationUtils {
@@ -38,6 +40,19 @@
                 MIN_ACCURACY + random.nextFloat() * (MAX_ACCURACY - MIN_ACCURACY));
     }
 
+    public static LocationResult createLocationResult(String provider, Random random) {
+        return LocationResult.wrap(createLocation(provider, random));
+    }
+
+    public static LocationResult createLocationResult(String provider, Random random,
+            int numLocations) {
+        Location[] locations = new Location[numLocations];
+        for (int i = 0; i < numLocations; i++) {
+            locations[i] = createLocation(provider, random);
+        }
+        return LocationResult.create(Arrays.asList(locations));
+    }
+
     public static Location createLocation(String provider, double latitude, double longitude,
             float accuracy) {
         Location location = new Location(provider);
@@ -48,4 +63,9 @@
         location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
         return location;
     }
+
+    public static LocationResult createLocationResult(String provider, double latitude,
+            double longitude, float accuracy) {
+        return LocationResult.wrap(createLocation(provider, latitude, longitude, accuracy));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
index 374fc77..28fd70a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
@@ -21,12 +21,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.location.Criteria;
 import android.location.Location;
+import android.location.LocationResult;
 import android.location.util.identity.CallerIdentity;
 import android.platform.test.annotations.Presubmit;
 
@@ -50,7 +52,7 @@
     private ProviderListenerCapture mListener;
 
     private AbstractLocationProvider mRealProvider;
-    private MockProvider mMockProvider;
+    private MockLocationProvider mMockProvider;
 
     private MockableLocationProvider mProvider;
 
@@ -60,7 +62,7 @@
         mListener = new ProviderListenerCapture(lock);
 
         mRealProvider = spy(new FakeProvider());
-        mMockProvider = spy(new MockProvider(new ProviderProperties(
+        mMockProvider = spy(new MockLocationProvider(new ProviderProperties(
                 false,
                 false,
                 false,
@@ -117,6 +119,20 @@
     }
 
     @Test
+    public void testFlush() {
+        Runnable listener = mock(Runnable.class);
+        mProvider.flush(listener);
+        verify(mRealProvider).onFlush(listener);
+        verify(listener).run();
+
+        listener = mock(Runnable.class);
+        mProvider.setMockProvider(mMockProvider);
+        mProvider.flush(listener);
+        verify(mMockProvider).onFlush(listener);
+        verify(listener).run();
+    }
+
+    @Test
     public void testSendExtraCommand() {
         mProvider.sendExtraCommand(0, 0, "command", null);
         verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null);
@@ -158,15 +174,15 @@
 
     @Test
     public void testReportLocation() {
-        Location realLocation = new Location("real");
-        Location mockLocation = new Location("mock");
+        LocationResult realLocation = LocationResult.create(new Location("real"));
+        LocationResult mockLocation = LocationResult.create(new Location("mock"));
 
         mRealProvider.reportLocation(realLocation);
-        assertThat(mListener.getNextLocation()).isEqualTo(realLocation);
+        assertThat(mListener.getNextLocationResult()).isEqualTo(realLocation);
 
         mProvider.setMockProvider(mMockProvider);
         mRealProvider.reportLocation(realLocation);
         mMockProvider.reportLocation(mockLocation);
-        assertThat(mListener.getNextLocation()).isEqualTo(mockLocation);
+        assertThat(mListener.getNextLocationResult()).isEqualTo(mockLocation);
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index 879b767..1df2854 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -23,7 +23,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -48,13 +47,11 @@
 import android.location.GnssNavigationMessage;
 import android.location.GnssRequest;
 import android.location.GnssSingleSatCorrection;
-import android.location.IBatchedLocationCallback;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
 import android.location.IGnssStatusListener;
 import android.location.INetInitiatedListener;
-import android.location.Location;
 import android.location.LocationManagerInternal;
 import android.os.Handler;
 import android.os.IBinder;
@@ -99,7 +96,6 @@
     @Mock private LocationManagerInternal mLocationManagerInternal;
     @Mock private GnssNative.GnssNativeInitNative mGnssInitNative;
     @Mock private GnssLocationProvider mMockGnssLocationProvider;
-    @Mock private GnssBatchingProvider mMockGnssBatchingProvider;
     @Mock private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider;
     @Mock private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider;
     @Mock private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
@@ -148,8 +144,6 @@
         // Setup GnssLocationProvider to return providers
         when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn(
                 mTestGnssStatusProvider);
-        when(mMockGnssLocationProvider.getGnssBatchingProvider()).thenReturn(
-                mMockGnssBatchingProvider);
         when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn(
                 mMockGnssCapabilitiesProvider);
         when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn(
@@ -165,10 +159,6 @@
         when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn(
                 mTestGnssAntennaInfoProvider);
 
-        // Setup GnssBatching provider
-        when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
-        when(mMockGnssBatchingProvider.stop()).thenReturn(true);
-
         // Create GnssManagerService
         mGnssManagerService = new GnssManagerService(mMockContext, mInjector,
                 mMockGnssLocationProvider);
@@ -204,12 +194,6 @@
         return mockListener;
     }
 
-    private IBatchedLocationCallback createMockBatchedLocationCallback() {
-        IBatchedLocationCallback mockedCallback = mock(IBatchedLocationCallback.class);
-        overrideAsBinder(mockedCallback);
-        return mockedCallback;
-    }
-
     private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() {
         IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class);
         overrideAsBinder(mockListener);
@@ -359,174 +343,6 @@
     }
 
     @Test
-    public void getGnssBatchSizeWithoutPermissionsTest() {
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class,
-                () -> mGnssManagerService.getGnssBatchSize());
-    }
-
-    @Test
-    public void getGnssBatchSizeWithPermissionsTest() {
-        final int gnssBatchSize = 10;
-        when(mMockGnssBatchingProvider.getBatchSize()).thenReturn(gnssBatchSize);
-        enableLocationPermissions();
-
-        assertThat(mGnssManagerService.getGnssBatchSize()).isEqualTo(
-                gnssBatchSize);
-    }
-
-    @Test
-    public void startGnssBatchWithoutPermissionsTest() {
-        final long periodNanos = 100L;
-        final boolean wakeOnFifoFull = true;
-
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class,
-                () -> mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
-                        TEST_PACKAGE, null));
-        verify(mMockGnssBatchingProvider, times(0)).start(periodNanos, wakeOnFifoFull);
-    }
-
-    @Test
-    public void startGnssBatchWithPermissionsTest() {
-        final long periodNanos = 100L;
-        final boolean wakeOnFifoFull = true;
-
-        enableLocationPermissions();
-
-        assertThat(mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
-                TEST_PACKAGE, null))
-                .isEqualTo(
-                        true);
-        verify(mMockGnssBatchingProvider, times(1)).start(100L, true);
-    }
-
-    @Test
-    public void addGnssBatchCallbackWithoutPermissionsTest() throws RemoteException {
-        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
-        List<Location> mockLocationList = new ArrayList<>();
-
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class, () -> mGnssManagerService.setGnssBatchingCallback(
-                mockBatchedLocationCallback, TEST_PACKAGE, null));
-
-        mGnssManagerService.onReportLocation(mockLocationList);
-
-        verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
-    }
-
-    @Test
-    public void addGnssBatchCallbackWithPermissionsTest() throws RemoteException {
-        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
-        List<Location> mockLocationList = new ArrayList<>();
-
-        enableLocationPermissions();
-
-        assertThat(mGnssManagerService.setGnssBatchingCallback(
-                mockBatchedLocationCallback, TEST_PACKAGE, null))
-                .isEqualTo(true);
-
-        mGnssManagerService.onReportLocation(mockLocationList);
-
-        verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
-    }
-
-    @Test
-    public void replaceGnssBatchCallbackTest() throws RemoteException {
-        IBatchedLocationCallback mockBatchedLocationCallback1 = createMockBatchedLocationCallback();
-        IBatchedLocationCallback mockBatchedLocationCallback2 = createMockBatchedLocationCallback();
-        List<Location> mockLocationList = new ArrayList<>();
-
-        enableLocationPermissions();
-
-        assertThat(mGnssManagerService.setGnssBatchingCallback(
-                mockBatchedLocationCallback1, TEST_PACKAGE, null))
-                .isEqualTo(true);
-        assertThat(mGnssManagerService.setGnssBatchingCallback(
-                mockBatchedLocationCallback2, TEST_PACKAGE, null))
-                .isEqualTo(true);
-
-        mGnssManagerService.onReportLocation(mockLocationList);
-
-        verify(mockBatchedLocationCallback1, times(0)).onLocationBatch(mockLocationList);
-        verify(mockBatchedLocationCallback2, times(1)).onLocationBatch(mockLocationList);
-    }
-
-    @Test
-    public void flushGnssBatchWithoutPermissionsTest() {
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class,
-                () -> mGnssManagerService.flushGnssBatch());
-        verify(mMockGnssBatchingProvider, times(0)).flush();
-    }
-
-    @Test
-    public void flushGnssBatchWithPermissionsTest() {
-        enableLocationPermissions();
-        mGnssManagerService.flushGnssBatch();
-
-        verify(mMockGnssBatchingProvider, times(1)).flush();
-    }
-
-    @Test
-    public void removeGnssBatchingCallbackWithoutPermissionsTest() throws RemoteException {
-        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
-        List<Location> mockLocationList = new ArrayList<>();
-
-        enableLocationPermissions();
-
-        mGnssManagerService.setGnssBatchingCallback(mockBatchedLocationCallback,
-                TEST_PACKAGE, null);
-
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class,
-                () -> mGnssManagerService.removeGnssBatchingCallback());
-
-        enableLocationPermissions();
-        mGnssManagerService.onReportLocation(mockLocationList);
-
-        verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
-    }
-
-    @Test
-    public void removeGnssBatchingCallbackWithPermissionsTest() throws RemoteException {
-        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
-        List<Location> mockLocationList = new ArrayList<>();
-
-        enableLocationPermissions();
-
-        mGnssManagerService.setGnssBatchingCallback(mockBatchedLocationCallback,
-                TEST_PACKAGE, null);
-
-        mGnssManagerService.removeGnssBatchingCallback();
-
-        mGnssManagerService.onReportLocation(mockLocationList);
-
-        verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
-    }
-
-    @Test
-    public void stopGnssBatchWithoutPermissionsTest() {
-        disableLocationPermissions();
-
-        assertThrows(SecurityException.class, () -> mGnssManagerService.stopGnssBatch());
-        verify(mMockGnssBatchingProvider, times(0)).stop();
-    }
-
-    @Test
-    public void stopGnssBatchWithPermissionsTest() {
-        enableLocationPermissions();
-
-        assertThat(mGnssManagerService.stopGnssBatch()).isEqualTo(true);
-        verify(mMockGnssBatchingProvider, times(1)).stop();
-    }
-
-    @Test
     public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException {
         final int timeToFirstFix = 20000;
         IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
index 2f1a20b..7a1a762 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
@@ -34,6 +34,11 @@
     protected void onSetRequest(ProviderRequest request) {}
 
     @Override
+    protected void onFlush(Runnable callback) {
+        callback.run();
+    }
+
+    @Override
     protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
 
     @Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
index 5e5ed11..c0c45e4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
@@ -18,18 +18,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.location.Location;
+import android.location.LocationResult;
 
 import com.android.server.location.AbstractLocationProvider;
 
 import java.util.LinkedList;
-import java.util.List;
 
 public class ProviderListenerCapture implements AbstractLocationProvider.Listener {
 
     private final Object mLock;
     private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>();
-    private final LinkedList<Location> mLocations = new LinkedList<>();
+    private final LinkedList<LocationResult> mLocations = new LinkedList<>();
 
     public ProviderListenerCapture(Object lock) {
         mLock = lock;
@@ -47,15 +46,12 @@
     }
 
     @Override
-    public void onReportLocation(Location location) {
+    public void onReportLocation(LocationResult locationResult) {
         assertThat(Thread.holdsLock(mLock)).isTrue();
-        mLocations.add(location);
+        mLocations.add(locationResult);
     }
 
-    public Location getNextLocation() {
+    public LocationResult getNextLocationResult() {
         return mLocations.poll();
     }
-
-    @Override
-    public void onReportLocation(List<Location> locations) {}
 }
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index d5483ff..83a597d 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -35,8 +35,8 @@
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.internal.R;
-import com.android.server.location.ComprehensiveCountryDetector;
-import com.android.server.location.CustomCountryDetectorTestClass;
+import com.android.server.location.countrydetector.ComprehensiveCountryDetector;
+import com.android.server.location.countrydetector.CustomCountryDetectorTestClass;
 
 import com.google.common.truth.Expect;
 
@@ -53,7 +53,7 @@
 public class CountryDetectorServiceTest {
 
     private static final String VALID_CUSTOM_TEST_CLASS =
-            "com.android.server.location.CustomCountryDetectorTestClass";
+            "com.android.server.location.countrydetector.CustomCountryDetectorTestClass";
     private static final String INVALID_CUSTOM_TEST_CLASS =
             "com.android.server.location.MissingCountryDetectorTestClass";
 
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index fba321e..5ddb571 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -39,11 +39,13 @@
 
 import android.app.AppOpsManager;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManagerInternal;
 import android.hardware.vibrator.IVibrator;
 import android.media.AudioAttributes;
+import android.media.AudioManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IVibratorStateListener;
@@ -61,11 +63,11 @@
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
-import android.test.mock.MockContentResolver;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -107,11 +109,13 @@
             new VibrationAttributes.Builder().setUsage(
                     VibrationAttributes.USAGE_RINGTONE).build();
 
-    @Rule public MockitoRule rule = MockitoJUnit.rule();
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
 
     @Mock private PackageManagerInternal mPackageManagerInternalMock;
     @Mock private PowerManagerInternal mPowerManagerInternalMock;
     @Mock private PowerSaveState mPowerSaveStateMock;
+    // TODO(b/131311651): replace with a FakeVibrator instead.
     @Mock private Vibrator mVibratorMock;
     @Mock private AppOpsManager mAppOpsManagerMock;
     @Mock private VibratorService.NativeWrapper mNativeWrapperMock;
@@ -126,9 +130,7 @@
         mTestLooper = new TestLooper();
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
 
-        MockContentResolver contentResolver = new MockContentResolver(mContextSpy);
-        contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
-
+        ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
         when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
         when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock);
@@ -144,28 +146,26 @@
         when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
                 .thenReturn(mPowerSaveStateMock);
 
-        setVibrationIntensityUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
-        setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
 
         addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
         addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
-        FakeSettingsProvider.clearSettingsProvider();
     }
 
     @After
     public void tearDown() throws Exception {
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
-        FakeSettingsProvider.clearSettingsProvider();
     }
 
     private VibratorService createService() {
-        return new VibratorService(mContextSpy,
+        VibratorService service = new VibratorService(mContextSpy,
                 new VibratorService.Injector() {
                     @Override
                     VibratorService.NativeWrapper getNativeWrapper() {
@@ -182,6 +182,8 @@
                         // ignore
                     }
                 });
+        service.systemReady();
+        return service;
     }
 
     @Test
@@ -305,9 +307,29 @@
     }
 
     @Test
+    public void vibrate_withRingtone_usesRingtoneSettings() {
+        setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
+        vibrate(createService(), VibrationEffect.createOneShot(1, 1), RINGTONE_ATTRS);
+
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
+        vibrate(createService(), VibrationEffect.createOneShot(10, 10), RINGTONE_ATTRS);
+
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
+        vibrate(createService(), VibrationEffect.createOneShot(100, 100), RINGTONE_ATTRS);
+
+        InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
+        inOrderVerifier.verify(mNativeWrapperMock, never()).vibratorOn(eq(1L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(10L), anyLong());
+        inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), anyLong());
+    }
+
+    @Test
     public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() {
         VibratorService service = createService();
-        service.systemReady();
 
         VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
         AudioAttributes audioAttributes = new AudioAttributes.Builder()
@@ -324,7 +346,6 @@
     @Test
     public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
         VibratorService service = createService();
-        service.systemReady();
 
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
         vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS);
@@ -624,14 +645,13 @@
     @Test
     public void scale_withPrebaked_userIntensitySettingAsEffectStrength() {
         // Alarm vibration is always VIBRATION_INTENSITY_HIGH.
-        setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_MEDIUM);
-        setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
-        setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
         VibratorService service = createService();
-        service.systemReady();
 
         vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
                 ALARM_ATTRS);
@@ -659,16 +679,15 @@
     public void scale_withOneShotAndWaveform_usesScaleLevelOnAmplitude() throws Exception {
         when(mVibratorMock.getDefaultNotificationVibrationIntensity())
                 .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
-        setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
-        setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
-        setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
 
         mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorService service = createService();
-        service.systemReady();
 
         vibrate(service, VibrationEffect.createOneShot(20, 100), ALARM_ATTRS);
         vibrate(service, VibrationEffect.createOneShot(20, 100), NOTIFICATION_ATTRS);
@@ -694,16 +713,15 @@
     public void scale_withComposed_usesScaleLevelOnPrimitiveScaleValues() {
         when(mVibratorMock.getDefaultNotificationVibrationIntensity())
                 .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
-        setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_HIGH);
-        setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_LOW);
-        setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
                 Vibrator.VIBRATION_INTENSITY_OFF);
 
         mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
         VibratorService service = createService();
-        service.systemReady();
 
         VibrationEffect effect = VibrationEffect.startComposition()
                 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
@@ -785,8 +803,18 @@
         LocalServices.addService(clazz, mock);
     }
 
-    private void setVibrationIntensityUserSetting(String settingName, int value) {
+    private void setRingerMode(int ringerMode) {
+        AudioManager audioManager = mContextSpy.getSystemService(AudioManager.class);
+        audioManager.setRingerModeInternal(ringerMode);
+        assertEquals(ringerMode, audioManager.getRingerMode());
+    }
+
+    private void setUserSetting(String settingName, int value) {
         Settings.System.putIntForUser(
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
     }
+
+    private void setGlobalSetting(String settingName, int value) {
+        Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
new file mode 100644
index 0000000..fb6266d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hdmi;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.hdmi.cec.config.CecSettings;
+import com.android.server.hdmi.cec.config.XmlParser;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+
+/**
+ *  Fake class which loads default system configuration with user-configurable
+ *  settings (useful for testing).
+ */
+final class FakeHdmiCecConfig extends HdmiCecConfig {
+    private static final String TAG = "FakeHdmiCecConfig";
+
+    private static final String SYSTEM_CONFIG_XML =
+            "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+                  + "<cec-settings>"
+                  + "  <setting name=\"send_standby_on_sleep\""
+                  + "           value-type=\"string\""
+                  + "           user-configurable=\"true\">"
+                  + "    <allowed-values>"
+                  + "      <value string-value=\"to_tv\" />"
+                  + "      <value string-value=\"broadcast\" />"
+                  + "      <value string-value=\"none\" />"
+                  + "    </allowed-values>"
+                  + "    <default-value string-value=\"to_tv\" />"
+                  + "  </setting>"
+                  + "</cec-settings>";
+
+    FakeHdmiCecConfig(@NonNull Context context) {
+        super(context, new StorageAdapter(), parseFromString(SYSTEM_CONFIG_XML), null);
+    }
+
+    private static CecSettings parseFromString(@NonNull String configXml) {
+        CecSettings config = null;
+        try {
+            config = XmlParser.read(
+                    new ByteArrayInputStream(configXml.getBytes()));
+        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+            Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
+        }
+        return config;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index c0dad52..647da95 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -25,6 +25,7 @@
 
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.os.Handler;
@@ -68,8 +69,10 @@
     private boolean mWokenUp;
     private boolean mStandby;
 
-    @Mock private IPowerManager mIPowerManagerMock;
-    @Mock private IThermalService mIThermalServiceMock;
+    @Mock
+    private IPowerManager mIPowerManagerMock;
+    @Mock
+    private IThermalService mIThermalServiceMock;
 
     @Before
     public void setUp() {
@@ -80,42 +83,42 @@
         PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
                 mIThermalServiceMock, new Handler(mMyLooper));
         mHdmiControlService =
-            new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
-                @Override
-                void wakeUp() {
-                    mWokenUp = true;
-                }
+                new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+                    @Override
+                    void wakeUp() {
+                        mWokenUp = true;
+                    }
 
-                @Override
-                void standby() {
-                    mStandby = true;
-                }
+                    @Override
+                    void standby() {
+                        mStandby = true;
+                    }
 
-                @Override
-                boolean isControlEnabled() {
-                    return true;
-                }
+                    @Override
+                    boolean isControlEnabled() {
+                        return true;
+                    }
 
-                @Override
-                boolean isPlaybackDevice() {
-                    return true;
-                }
+                    @Override
+                    boolean isPlaybackDevice() {
+                        return true;
+                    }
 
-                @Override
-                void writeStringSystemProperty(String key, String value) {
-                    // do nothing
-                }
+                    @Override
+                    void writeStringSystemProperty(String key, String value) {
+                        // do nothing
+                    }
 
-                @Override
-                boolean isPowerStandby() {
-                    return false;
-                }
+                    @Override
+                    boolean isPowerStandby() {
+                        return false;
+                    }
 
-                @Override
-                PowerManager getPowerManager() {
-                    return powerManager;
-                }
-            };
+                    @Override
+                    PowerManager getPowerManager() {
+                        return powerManager;
+                    }
+                };
 
         mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService);
         mHdmiCecLocalDevicePlayback.init();
@@ -229,8 +232,8 @@
     public void handleRoutingChange_WakeUpAndSendActiveSource() {
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties
-                    .playback_device_action_on_routing_control_values
-                    .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+                        .playback_device_action_on_routing_control_values
+                        .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
 
         mWokenUp = false;
 
@@ -252,8 +255,8 @@
     public void handleRoutingInformation_WakeUpAndSendActiveSource() {
         mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
                 HdmiProperties
-                    .playback_device_action_on_routing_control_values
-                    .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+                        .playback_device_action_on_routing_control_values
+                        .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
 
         mWokenUp = false;
 
@@ -732,10 +735,10 @@
     @Test
     public void handleActiveSource_ActiveSource_None() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
         mStandby = false;
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
-                                         mPlaybackPhysicalAddress);
+                mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isFalse();
@@ -749,7 +752,7 @@
     @Test
     public void handleActiveSource_notActiveSource_None() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+                HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
         mStandby = false;
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
@@ -765,10 +768,10 @@
     @Test
     public void handleActiveSource_ActiveSource_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
         mStandby = false;
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
-                                         mPlaybackPhysicalAddress);
+                mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
         mTestLooper.dispatchAll();
         assertThat(mStandby).isFalse();
@@ -778,7 +781,7 @@
     @Test
     public void handleActiveSource_notActiveSource_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
         mStandby = false;
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
@@ -1036,7 +1039,7 @@
     @Test
     public void handleSetStreamPath_otherDevice_StandbyNow() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
@@ -1050,7 +1053,7 @@
     @Test
     public void handleSetStreamPath_otherDevice_StandbyNow_InactiveSource() {
         mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
-            HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+                HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
         mStandby = false;
@@ -1129,4 +1132,46 @@
         assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(systemAudioModeRequest);
     }
+
+    @Test
+    public void getActiveSource_noActiveSource() {
+        mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+                Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getActiveSource()).isNull();
+    }
+
+    @Test
+    public void getActiveSource_localPlaybackIsActiveSource() {
+        mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
+                mHdmiControlService.getPhysicalAddress(), "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
+                mHdmiCecLocalDevicePlayback.getDeviceInfo());
+    }
+
+    @Test
+    public void getActiveSource_deviceInNetworkIsActiveSource() {
+        HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x3000, 0,
+                Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(externalDevice);
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+                externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getActiveSource()).isEqualTo(externalDevice);
+    }
+
+    @Test
+    public void getActiveSource_unknownDeviceIsActiveSource() {
+        HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x3000, 0,
+                Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+
+        mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+                externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
+                externalDevice.getPhysicalAddress());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index e54f2c9..2f49fb7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -42,6 +42,8 @@
 import org.junit.runners.JUnit4;
 
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 @SmallTest
 @Presubmit
@@ -80,6 +82,21 @@
 
         @Override
         protected void setPreferredAddress(int addr) {}
+
+        @Override
+        protected int getRcProfile() {
+            return 0;
+        }
+
+        @Override
+        protected List<Integer> getRcFeatures() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        protected List<Integer> getDeviceFeatures() {
+            return Collections.emptyList();
+        }
     }
 
     private MyHdmiCecLocalDevice mHdmiLocalDevice;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index bf4851b..aa72d07 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -23,6 +23,7 @@
 
 import android.content.Context;
 import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
 import android.os.Handler;
@@ -136,4 +137,51 @@
                 ADDR_PLAYBACK_1);
         assertThat(mNativeWrapper.getResultMessages()).contains(givePhysicalAddress);
     }
+
+    @Test
+    public void getActiveSource_noActiveSource() {
+        mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+                Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+        mHdmiCecLocalDeviceTv.setActivePath(HdmiDeviceInfo.PATH_INVALID);
+
+        assertThat(mHdmiControlService.getActiveSource()).isNull();
+    }
+
+    @Test
+    public void getActiveSource_deviceInNetworkIsActiveSource() {
+        HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x1000, 0,
+                Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+        mHdmiControlService.getHdmiCecNetwork().addCecDevice(externalDevice);
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+                externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+        assertThat(mHdmiControlService.getActiveSource()).isEqualTo(externalDevice);
+    }
+
+    @Test
+    public void getActiveSource_unknownLogicalAddressInNetworkIsActiveSource() {
+        HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(0x1000, 1);
+
+        mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+                externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+        mHdmiCecLocalDeviceTv.setActivePath(0x1000);
+
+        assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
+                externalDevice);
+    }
+
+    @Test
+    public void getActiveSource_unknownDeviceIsActiveSource() {
+        HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x1000, 0,
+                Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+
+        mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+                externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+        mHdmiCecLocalDeviceTv.setActivePath(0x1000);
+
+        assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
+                externalDevice.getPhysicalAddress());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index f17173f..6882ec1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -26,10 +26,14 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.google.android.collect.Lists;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.util.Collections;
+
 @SmallTest
 @Presubmit
 @RunWith(JUnit4.class)
@@ -88,6 +92,98 @@
                 buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
     }
 
+    @Test
+    public void buildGiveFeatures() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildGiveFeatures(ADDR_PLAYBACK_1, ADDR_TV);
+
+        assertThat(message).isEqualTo(buildMessage("40:A5"));
+    }
+
+    @Test
+    public void buildReportFeatures_basicTv_1_4() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_1_4,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:05:80:00:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_basicPlayback_1_4() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1,
+                Constants.VERSION_1_4,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("4F:A6:05:10:00:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_basicPlaybackAudioSystem_1_4() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1,
+                Constants.VERSION_1_4,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK,
+                        HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("4F:A6:05:18:00:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_basicTv_2_0() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_2_0,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_remoteControlTv_2_0() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_2_0,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_ONE), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:02:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_remoteControlPlayback_2_0() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_2_0,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE,
+                Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                        Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU), Collections.emptyList());
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:00"));
+    }
+
+    @Test
+    public void buildReportFeatures_deviceFeaturesTv_2_0() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_2_0,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+                Lists.newArrayList(Constants.RC_PROFILE_TV_NONE),
+                Lists.newArrayList(Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN));
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:40"));
+    }
+
+    @Test
+    public void buildReportFeatures_deviceFeaturesPlayback_2_0() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+                Constants.VERSION_2_0,
+                Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE,
+                Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+                        Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU),
+                Lists.newArrayList(Constants.DEVICE_FEATURE_SUPPORTS_DECK_CONTROL));
+
+        assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:10"));
+    }
+
     /**
      * Build a CEC message from a hex byte string with bytes separated by {@code :}.
      *
@@ -100,7 +196,7 @@
         int opcode = Integer.parseInt(parts[1], 16);
         byte[] params = new byte[parts.length - 2];
         for (int i = 0; i < params.length; i++) {
-            params[i] = Byte.parseByte(parts[i + 2], 16);
+            params[i] = (byte) Integer.parseInt(parts[i + 2], 16);
         }
         return new HdmiCecMessage(src, dest, opcode, params);
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index 553df3b..c1532f2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -353,6 +353,24 @@
         assertMessageValidity("40:35:EE:52:4A").isEqualTo(ERROR_PARAMETER);
     }
 
+    @Test
+    public void isValid_giveFeatures() {
+        assertMessageValidity("40:A5").isEqualTo(OK);
+
+        assertMessageValidity("4F:A5").isEqualTo(ERROR_DESTINATION);
+        assertMessageValidity("F0:A5").isEqualTo(ERROR_SOURCE);
+    }
+
+    @Test
+    public void isValid_reportFeatures() {
+        assertMessageValidity("0F:A6:05:80:00:00").isEqualTo(OK);
+
+        assertMessageValidity("04:A6:05:80:00:00").isEqualTo(ERROR_DESTINATION);
+        assertMessageValidity("FF:A6:05:80:00:00").isEqualTo(ERROR_SOURCE);
+
+        assertMessageValidity("0F:A6").isEqualTo(ERROR_PARAMETER_SHORT);
+    }
+
     private IntegerSubject assertMessageValidity(String message) {
         return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message)));
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
index 74a0052..c212bf8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
@@ -38,6 +38,8 @@
 import org.junit.runners.JUnit4;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Tests for {@link HdmiControlServiceBinderAPITest} class.
@@ -99,6 +101,21 @@
         protected void setCanGoToStandby(boolean canGoToStandby) {
             mCanGoToStandby = canGoToStandby;
         }
+
+        @Override
+        protected int getRcProfile() {
+            return 0;
+        }
+
+        @Override
+        protected List<Integer> getRcFeatures() {
+            return Collections.emptyList();
+        }
+
+        @Override
+        protected List<Integer> getDeviceFeatures() {
+            return Collections.emptyList();
+        }
     }
 
     private static final String TAG = "HdmiControlServiceBinderAPITest";
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 68b46c4..dea3896 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -54,6 +54,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Tests for {@link HdmiControlService} class.
@@ -421,6 +422,42 @@
         assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0);
     }
 
+    @Test
+    public void handleGiveFeatures_cec14_featureAbort() {
+        Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
+                Constants.VERSION_1_4);
+        mHdmiControlService.setControlEnabled(true);
+        mTestLooper.dispatchAll();
+
+        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1));
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+                Constants.ADDR_PLAYBACK_1, Constants.ADDR_TV, Constants.MESSAGE_GIVE_FEATURES,
+                Constants.ABORT_UNRECOGNIZED_OPCODE);
+        assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
+    }
+
+    @Test
+    public void handleGiveFeatures_cec20_reportsFeatures() {
+        Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
+                Constants.VERSION_2_0);
+        mHdmiControlService.setControlEnabled(true);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
+                Constants.ADDR_PLAYBACK_1));
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
+                Constants.ADDR_PLAYBACK_1, Constants.VERSION_2_0,
+                Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
+                mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
+                mMyPlaybackDevice.getDeviceFeatures());
+        assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
+    }
 
     private static class VolumeControlFeatureCallback extends
             IHdmiCecVolumeControlFeatureListener.Stub {
diff --git a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
rename to services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java
index 98966c0..41cfa62 100644
--- a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,10 +11,10 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.location.Country;
 import android.location.CountryListener;
diff --git a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.java
similarity index 89%
rename from services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java
rename to services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.java
index e159012..fc19a94 100644
--- a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.content.Context;
 import android.location.Country;
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
rename to services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java
index 5f5d668..46269eb 100644
--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,9 +11,9 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
-package com.android.server.location;
+package com.android.server.location.countrydetector;
 
 import android.location.Country;
 import android.location.CountryListener;
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
new file mode 100644
index 0000000..fa171fd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -0,0 +1,238 @@
+/*
+ * 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.vibrator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Handler;
+import android.os.IExternalVibratorService;
+import android.os.UserHandle;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
+
+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 VibrationScaler}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibrationScalerTest
+ */
+@Presubmit
+public class VibrationScalerTest {
+
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+
+    // TODO(b/131311651): replace with a FakeVibrator instead.
+    @Mock private Vibrator mVibratorMock;
+
+    private TestLooper mTestLooper;
+    private ContextWrapper mContextSpy;
+    private VibrationSettings mVibrationSettings;
+    private VibrationScaler mVibrationScaler;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+
+        ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
+        when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+
+        mVibrationSettings = new VibrationSettings(
+                mContextSpy, new Handler(mTestLooper.getLooper()));
+        mVibrationScaler = new VibrationScaler(mContextSpy, mVibrationSettings);
+    }
+
+    @Test
+    public void testGetExternalVibrationScale() {
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        assertEquals(IExternalVibratorService.SCALE_VERY_HIGH,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        assertEquals(IExternalVibratorService.SCALE_HIGH,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+        assertEquals(IExternalVibratorService.SCALE_NONE,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        assertEquals(IExternalVibratorService.SCALE_LOW,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        assertEquals(IExternalVibratorService.SCALE_VERY_LOW,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        // Unexpected vibration intensity will be treated as SCALE_NONE.
+        assertEquals(IExternalVibratorService.SCALE_NONE,
+                mVibrationScaler.getExternalVibrationScale(VibrationAttributes.USAGE_TOUCH));
+    }
+
+    @Test
+    public void scale_withPrebaked_setsEffectStrengthBasedOnSettings() {
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+
+        VibrationEffect.Prebaked scaled = mVibrationScaler.scale(
+                effect, VibrationAttributes.USAGE_NOTIFICATION);
+        assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
+        assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_MEDIUM);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+        scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
+        assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_LIGHT);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        scaled = mVibrationScaler.scale(effect, VibrationAttributes.USAGE_NOTIFICATION);
+        // Unexpected intensity setting will be mapped to STRONG.
+        assertEquals(scaled.getEffectStrength(), VibrationEffect.EFFECT_STRENGTH_STRONG);
+    }
+
+    @Test
+    public void scale_withOneShotAndWaveform_resolvesAmplitude() {
+        // No scale, default amplitude still resolved
+        when(mVibratorMock.getDefaultRingVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+
+        VibrationEffect.OneShot oneShot = mVibrationScaler.scale(
+                VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE),
+                VibrationAttributes.USAGE_RINGTONE);
+        assertTrue(oneShot.getAmplitude() > 0);
+
+        VibrationEffect.Waveform waveform = mVibrationScaler.scale(
+                VibrationEffect.createWaveform(new long[]{10},
+                        new int[]{VibrationEffect.DEFAULT_AMPLITUDE}, -1),
+                VibrationAttributes.USAGE_RINGTONE);
+        assertTrue(waveform.getAmplitudes()[0] > 0);
+    }
+
+    @Test
+    public void scale_withOneShotWaveform_scalesAmplitude() {
+        when(mVibratorMock.getDefaultRingVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_MEDIUM);
+
+        VibrationEffect.OneShot oneShot = mVibrationScaler.scale(
+                VibrationEffect.createOneShot(100, 100), VibrationAttributes.USAGE_RINGTONE);
+        // Ringtone scales up.
+        assertTrue(oneShot.getAmplitude() > 100);
+
+        VibrationEffect.Waveform waveform = mVibrationScaler.scale(
+                VibrationEffect.createWaveform(new long[]{100}, new int[]{100}, -1),
+                VibrationAttributes.USAGE_NOTIFICATION);
+        // Notification scales down.
+        assertTrue(waveform.getAmplitudes()[0] < 100);
+
+        oneShot = mVibrationScaler.scale(VibrationEffect.createOneShot(100, 100),
+                VibrationAttributes.USAGE_TOUCH);
+        // Haptic feedback does not scale.
+        assertEquals(100, oneShot.getAmplitude());
+    }
+
+    @Test
+    public void scale_withComposed_scalesPrimitives() {
+        when(mVibratorMock.getDefaultRingVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_MEDIUM);
+
+        VibrationEffect composed = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 0.5f).compose();
+
+        VibrationEffect.Composed scaled = mVibrationScaler.scale(composed,
+                VibrationAttributes.USAGE_RINGTONE);
+        // Ringtone scales up.
+        assertTrue(scaled.getPrimitiveEffects().get(0).scale > 0.5f);
+
+        scaled = mVibrationScaler.scale(composed, VibrationAttributes.USAGE_NOTIFICATION);
+        // Notification scales down.
+        assertTrue(scaled.getPrimitiveEffects().get(0).scale < 0.5f);
+
+        scaled = mVibrationScaler.scale(composed, VibrationAttributes.USAGE_TOUCH);
+        // Haptic feedback does not scale.
+        assertEquals(0.5, scaled.getPrimitiveEffects().get(0).scale, 1e-5);
+    }
+
+    private void setUserSetting(String settingName, int value) {
+        Settings.System.putIntForUser(
+                mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+        // FakeSettingsProvider don't support testing triggering ContentObserver yet.
+        mVibrationSettings.updateSettings();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
new file mode 100644
index 0000000..8aa0e3fe
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.vibrator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.VibrationAttributes;
+import android.os.Vibrator;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
+
+import org.junit.After;
+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 VibrationSettings}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:VibrationSettingsTest
+ */
+@Presubmit
+public class VibrationSettingsTest {
+
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+
+    // TODO(b/131311651): replace with a FakeVibrator instead.
+    @Mock private Vibrator mVibratorMock;
+    @Mock private VibrationSettings.OnVibratorSettingsChanged mListenerMock;
+
+    private TestLooper mTestLooper;
+    private ContextWrapper mContextSpy;
+    private AudioManager mAudioManager;
+    private VibrationSettings mVibrationSettings;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+
+        ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
+        when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
+        when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+        when(mVibratorMock.hasVibrator()).thenReturn(true);
+
+        mAudioManager = mContextSpy.getSystemService(AudioManager.class);
+        mVibrationSettings = new VibrationSettings(
+                mContextSpy, new Handler(mTestLooper.getLooper()));
+
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FakeSettingsProvider.clearSettingsProvider();
+    }
+
+    @Test
+    public void addListener_settingsChangeTriggerListener() {
+        mVibrationSettings.addListener(mListenerMock);
+
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+
+        verify(mListenerMock, times(7)).onChange();
+    }
+
+    @Test
+    public void removeListener_noMoreCallbacksToListener() {
+        mVibrationSettings.addListener(mListenerMock);
+
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        verify(mListenerMock).onChange();
+
+        mVibrationSettings.removeListener(mListenerMock);
+
+        verifyNoMoreInteractions(mListenerMock);
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
+    }
+
+    @Test
+    public void shouldVibrateForRingtones_withVibrateWhenRinging_onlyIgnoreSettingsForSilentMode() {
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
+        assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+        assertFalse(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
+        assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
+        assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
+        assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+    }
+
+    @Test
+    public void shouldVibrateForRingtones_withApplyRampingRinger_onlyIgnoreSettingsForSilentMode() {
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 1);
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
+        assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+        assertFalse(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
+        assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
+        assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
+        assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+    }
+
+    @Test
+    public void shouldVibrateForRingtones_withAllSettingsOff_onlyVibratesForVibrateMode() {
+        setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0);
+        setGlobalSetting(Settings.Global.APPLY_RAMPING_RINGER, 0);
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE);
+        assertEquals(AudioManager.RINGER_MODE_VIBRATE, mAudioManager.getRingerMode());
+        assertTrue(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_SILENT);
+        assertEquals(AudioManager.RINGER_MODE_SILENT, mAudioManager.getRingerMode());
+        assertFalse(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_MAX);
+        assertEquals(AudioManager.RINGER_MODE_MAX, mAudioManager.getRingerMode());
+        assertFalse(mVibrationSettings.shouldVibrateForRingtone());
+
+        mAudioManager.setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL);
+        assertEquals(AudioManager.RINGER_MODE_NORMAL, mAudioManager.getRingerMode());
+        assertFalse(mVibrationSettings.shouldVibrateForRingtone());
+    }
+
+    @Test
+    public void shouldVibrateInputDevices_returnsSettingsValue() {
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1);
+        assertTrue(mVibrationSettings.shouldVibrateInputDevices());
+
+        setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
+        assertFalse(mVibrationSettings.shouldVibrateInputDevices());
+    }
+
+    @Test
+    public void isInZenMode_returnsSettingsValue() {
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        assertFalse(mVibrationSettings.isInZenMode());
+
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
+        assertTrue(mVibrationSettings.isInZenMode());
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_ALARMS);
+        assertTrue(mVibrationSettings.isInZenMode());
+
+        setGlobalSetting(Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        assertFalse(mVibrationSettings.isInZenMode());
+
+        setGlobalSetting(Settings.Global.ZEN_MODE,
+                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        assertTrue(mVibrationSettings.isInZenMode());
+    }
+
+    @Test
+    public void getDefaultIntensity_returnsIntensityFromVibratorService() {
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_HIGH);
+        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        when(mVibratorMock.getDefaultRingVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_LOW);
+
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_OFF);
+
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_ALARM));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_TOUCH));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_UNKNOWN));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getDefaultIntensity(
+                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getDefaultIntensity(VibrationAttributes.USAGE_RINGTONE));
+    }
+
+    @Test
+    public void getCurrentIntensity_returnsIntensityFromSettings() {
+        when(mVibratorMock.getDefaultHapticFeedbackIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
+        when(mVibratorMock.getDefaultNotificationVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
+        when(mVibratorMock.getDefaultRingVibrationIntensity())
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_OFF);
+
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_MEDIUM);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+                Vibrator.VIBRATION_INTENSITY_LOW);
+
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_ALARM));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_HIGH,
+                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_TOUCH));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_NOTIFICATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_UNKNOWN));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_MEDIUM,
+                mVibrationSettings.getCurrentIntensity(
+                        VibrationAttributes.USAGE_PHYSICAL_EMULATION));
+        assertEquals(Vibrator.VIBRATION_INTENSITY_LOW,
+                mVibrationSettings.getCurrentIntensity(VibrationAttributes.USAGE_RINGTONE));
+    }
+
+    private void setUserSetting(String settingName, int value) {
+        Settings.System.putIntForUser(
+                mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
+        // FakeSettingsProvider don't support testing triggering ContentObserver yet.
+        mVibrationSettings.updateSettings();
+    }
+
+    private void setGlobalSetting(String settingName, int value) {
+        Settings.Global.putInt(mContextSpy.getContentResolver(), settingName, value);
+        // FakeSettingsProvider don't support testing triggering ContentObserver yet.
+        mVibrationSettings.updateSettings();
+        mAudioManager.reloadAudioSettings();
+    }
+}
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 a7ced1d..c05eb8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -662,8 +662,8 @@
         ai.uid = callingUid;
         ai.packageName = "com.android.test.package";
         final WindowProcessController callerApp =
-                new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener);
-        callerApp.setHasForegroundActivities(hasForegroundActivities);
+                spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener));
+        doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities();
         doReturn(callerApp).when(mAtm).getProcessController(caller);
         // caller is recents
         RecentTasks recentTasks = mock(RecentTasks.class);
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 21be6ef..5afcedb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -22,6 +22,9 @@
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -168,11 +171,7 @@
                 mAtm, applicationInfo, null, 0, -1, null, mMockListener);
         wpc.setThread(mock(IApplicationThread.class));
 
-        final ActivityRecord activity = new ActivityBuilder(mAtm)
-                .setCreateTask(true)
-                .setUseProcess(wpc)
-                .build();
-
+        final ActivityRecord activity = createActivityRecord(wpc);
         wpc.addActivityIfNeeded(activity);
         // System UI owned processes should not be registered for activity config changes.
         assertFalse(wpc.registeredForActivityConfigChanges());
@@ -185,11 +184,7 @@
         // Notify WPC that this process has started an IME service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mAtm)
-                .setCreateTask(true)
-                .setUseProcess(mWpc)
-                .build();
-
+        final ActivityRecord activity = createActivityRecord(mWpc);
         mWpc.addActivityIfNeeded(activity);
         // IME processes should not be registered for activity config changes.
         assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -202,11 +197,7 @@
         // Notify WPC that this process has started an ally service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mAtm)
-                .setCreateTask(true)
-                .setUseProcess(mWpc)
-                .build();
-
+        final ActivityRecord activity = createActivityRecord(mWpc);
         mWpc.addActivityIfNeeded(activity);
         // Ally processes should not be registered for activity config changes.
         assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -219,11 +210,7 @@
         // Notify WPC that this process has started an voice interaction service.
         mWpc.onServiceStarted(serviceInfo);
 
-        final ActivityRecord activity = new ActivityBuilder(mAtm)
-                .setCreateTask(true)
-                .setUseProcess(mWpc)
-                .build();
-
+        final ActivityRecord activity = createActivityRecord(mWpc);
         mWpc.addActivityIfNeeded(activity);
         // Voice interaction service processes should not be registered for activity config changes.
         assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -244,7 +231,7 @@
         final int globalSeq = 100;
         mRootWindowContainer.getConfiguration().seq = globalSeq;
         invertOrientation(mWpc.getConfiguration());
-        new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(mWpc).build();
+        createActivityRecord(mWpc);
 
         assertTrue(mWpc.registeredForActivityConfigChanges());
         assertEquals("Config seq of process should not be affected by activity",
@@ -253,10 +240,7 @@
 
     @Test
     public void testComputeOomAdjFromActivities() {
-        final ActivityRecord activity = new ActivityBuilder(mAtm)
-                .setCreateTask(true)
-                .setUseProcess(mWpc)
-                .build();
+        final ActivityRecord activity = createActivityRecord(mWpc);
         activity.mVisibleRequested = true;
         final int[] callbackResult = { 0 };
         final int visible = 1;
@@ -308,6 +292,41 @@
         assertEquals(other, callbackResult[0]);
     }
 
+    @Test
+    public void testComputeProcessActivityState() {
+        final VisibleActivityProcessTracker tracker = mAtm.mVisibleActivityProcessTracker;
+        spyOn(tracker);
+        final ActivityRecord activity = createActivityRecord(mWpc);
+        activity.mVisibleRequested = true;
+        activity.setState(Task.ActivityState.STARTED, "test");
+
+        verify(tracker).onAnyActivityVisible(mWpc);
+        assertTrue(mWpc.hasVisibleActivities());
+
+        activity.setState(Task.ActivityState.RESUMED, "test");
+
+        verify(tracker).onActivityResumedWhileVisible(mWpc);
+        assertTrue(tracker.hasResumedActivity(mWpc.mUid));
+
+        activity.makeFinishingLocked();
+        activity.setState(Task.ActivityState.PAUSING, "test");
+
+        assertFalse(tracker.hasResumedActivity(mWpc.mUid));
+        assertTrue(mWpc.hasForegroundActivities());
+
+        activity.setVisibility(false);
+        activity.mVisibleRequested = false;
+        activity.setState(Task.ActivityState.STOPPED, "test");
+
+        verify(tracker).onAllActivitiesInvisible(mWpc);
+        assertFalse(mWpc.hasVisibleActivities());
+        assertFalse(mWpc.hasForegroundActivities());
+    }
+
+    private ActivityRecord createActivityRecord(WindowProcessController wpc) {
+        return new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(wpc).build();
+    }
+
     private TestDisplayContent createTestDisplayContentInContainer() {
         return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
     }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ae485d5..b335a90 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -373,6 +373,14 @@
             "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
 
     /**
+     * A string value for {@link #EXTRA_CALL_DISCONNECT_MESSAGE}, indicates the call was dropped by
+     * lower layers
+     * @hide
+     */
+    public static final String CALL_AUTO_DISCONNECT_MESSAGE_STRING =
+            "Call dropped by lower layers";
+
+    /**
      * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
      * containing the component name of the associated connection service.
      * @hide
@@ -984,8 +992,6 @@
      * <p>
      * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
      *
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
-     *
      * @param uriScheme The URI scheme.
      * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
      */
@@ -1162,8 +1168,6 @@
      * calls. The returned list includes only those accounts which have been explicitly enabled
      * by the user.
      *
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
-     *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
      */
@@ -1466,9 +1470,6 @@
      *         the specified package does not correspond to an installed dialer, or is already
      *         the default dialer.
      *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
-     * Requires permission: {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
-     *
      * @hide
      * @deprecated Use
      * {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, UserHandle,
@@ -1512,8 +1513,6 @@
      * Return whether a given phone number is the configured voicemail number for a
      * particular phone account.
      *
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
-     *
      * @param accountHandle The handle for the account to check the voicemail number against
      * @param number The number to look up.
      */
@@ -1533,8 +1532,6 @@
     /**
      * Return the voicemail number for a given phone account.
      *
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
-     *
      * @param accountHandle The handle for the phone account.
      * @return The voicemail number for the phone account, and {@code null} if one has not been
      *         configured.
@@ -1586,8 +1583,6 @@
     /**
      * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
      * states) originating from either a manager or self-managed {@link ConnectionService}.
-     * <p>
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
      *
      * @return {@code true} if there is an ongoing call in either a managed or self-managed
      *      {@link ConnectionService}, {@code false} otherwise.
@@ -1636,8 +1631,6 @@
      * <p>
      * If you also need to know if there are ongoing self-managed calls, use {@link #isInCall()}
      * instead.
-     * <p>
-     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
      *
      * @return {@code true} if there is an ongoing call in a managed {@link ConnectionService},
      *      {@code false} otherwise.
@@ -1711,8 +1704,6 @@
      * If there is a ringing call, calling this method rejects the ringing call.  Otherwise the
      * foreground call is ended.
      * <p>
-     * Requires permission {@link android.Manifest.permission#ANSWER_PHONE_CALLS}.
-     * <p>
      * Note: this method CANNOT be used to end ongoing emergency calls and will return {@code false}
      * if an attempt is made to end an emergency call.
      *
@@ -1742,9 +1733,6 @@
      * the incoming call requests.  This means, for example, that an incoming call requesting
      * {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
      *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
-     * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
-     *
      * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
      * instead.
      */
@@ -1767,9 +1755,6 @@
      * If there is a ringing incoming call, this method accepts the call on behalf of the user,
      * with the specified video state.
      *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
-     * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
-     *
      * @param videoState The desired video state to answer the call with.
      * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
      * instead.
@@ -1981,8 +1966,6 @@
      * Requires that the method-caller be set as the system dialer app.
      * </p>
      *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
-     *
      * @param dialString The digits to dial.
      * @return True if the digits were processed as an MMI code, false otherwise.
      */
@@ -2007,8 +1990,6 @@
      * Requires that the method-caller be set as the system dialer app.
      * </p>
      *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
-     *
      * @param accountHandle The handle for the account the MMI code should apply to.
      * @param dialString The digits to dial.
      * @return True if the digits were processed as an MMI code, false otherwise.
@@ -2028,8 +2009,8 @@
     }
 
     /**
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
-     *
+     * Returns a URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
+     * for ADN content retrieval.
      * @param accountHandle The handle for the account to derive an adn query URI for or
      * {@code null} to return a URI which will use the default account.
      * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
@@ -2053,8 +2034,6 @@
      * <p>
      * Requires that the method-caller be set as the system dialer app.
      * </p>
-     *
-     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void cancelMissedCallsNotification() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 89d24cb..e65b641 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9380,11 +9380,22 @@
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
      *
-     * @return one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, {@link #CDMA_ROAMING_MODE_HOME},
-     * {@link #CDMA_ROAMING_MODE_AFFILIATED}, {@link #CDMA_ROAMING_MODE_ANY}.
+     * @return the CDMA roaming mode.
+     * @throws SecurityException if the caller does not have the permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     *
+     * @see #CDMA_ROAMING_MODE_RADIO_DEFAULT
+     * @see #CDMA_ROAMING_MODE_HOME
+     * @see #CDMA_ROAMING_MODE_AFFILIATED
+     * @see #CDMA_ROAMING_MODE_ANY
+     *
+     * <p>Requires permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @CdmaRoamingMode int getCdmaRoamingMode() {
         int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT;
@@ -9392,9 +9403,12 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 mode = telephony.getCdmaRoamingMode(getSubId());
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "Error calling ITelephony#getCdmaRoamingMode", ex);
+            ex.rethrowFromSystemServer();
         }
         return mode;
     }
@@ -9405,25 +9419,36 @@
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
      *
-     * @param mode should be one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT},
-     * {@link #CDMA_ROAMING_MODE_HOME}, {@link #CDMA_ROAMING_MODE_AFFILIATED},
-     * {@link #CDMA_ROAMING_MODE_ANY}.
+     * @param mode CDMA roaming mode.
+     * @throws SecurityException if the caller does not have the permission.
+     * @throws IllegalStateException if the Telephony process or radio is not currently available.
      *
-     * @return {@code true} if successed.
+     * @see #CDMA_ROAMING_MODE_RADIO_DEFAULT
+     * @see #CDMA_ROAMING_MODE_HOME
+     * @see #CDMA_ROAMING_MODE_AFFILIATED
+     * @see #CDMA_ROAMING_MODE_ANY
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setCdmaRoamingMode(@CdmaRoamingMode int mode) {
+    public void setCdmaRoamingMode(@CdmaRoamingMode int mode) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.setCdmaRoamingMode(getSubId(), mode);
+                boolean result = telephony.setCdmaRoamingMode(getSubId(), mode);
+                if (!result) throw new IllegalStateException("radio is unavailable.");
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "Error calling ITelephony#setCdmaRoamingMode", ex);
+            ex.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /** @hide */
@@ -9435,48 +9460,94 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface CdmaSubscription{}
 
-    /** Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source.
+    /**
+     * Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source.
      * @hide
      */
+    @SystemApi
     public static final int CDMA_SUBSCRIPTION_UNKNOWN  = -1;
 
-    /** Used for CDMA subscription mode: RUIM/SIM (default)
+    /**
+     * Used for CDMA subscription mode: RUIM/SIM (default)
      * @hide
      */
+    @SystemApi
     public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0;
 
-    /** Used for CDMA subscription mode: NV -> non-volatile memory
+    /**
+     * Used for CDMA subscription mode: NV -> non-volatile memory
      * @hide
      */
+    @SystemApi
     public static final int CDMA_SUBSCRIPTION_NV       = 1;
 
-    /** @hide */
-    public static final int PREFERRED_CDMA_SUBSCRIPTION = CDMA_SUBSCRIPTION_RUIM_SIM;
-
     /**
-     * Sets the subscription mode for CDMA phone to the given mode {@code mode}.
+     * Gets the subscription mode for CDMA phone.
      *
-     * @param mode CDMA subscription mode
-     *
-     * @return {@code true} if successed.
+     * @return the CDMA subscription mode.
+     * @throws SecurityException if the caller does not have the permission.
+     * @throws IllegalStateException if the Telephony process or radio is not currently available.
      *
      * @see #CDMA_SUBSCRIPTION_UNKNOWN
      * @see #CDMA_SUBSCRIPTION_RUIM_SIM
      * @see #CDMA_SUBSCRIPTION_NV
      *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setCdmaSubscriptionMode(@CdmaSubscription int mode) {
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @CdmaSubscription int getCdmaSubscriptionMode() {
+        int mode = CDMA_SUBSCRIPTION_RUIM_SIM;
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.setCdmaSubscriptionMode(getSubId(), mode);
+                mode = telephony.getCdmaSubscriptionMode(getSubId());
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Error calling ITelephony#getCdmaSubscriptionMode", ex);
+            ex.rethrowFromSystemServer();
+        }
+        return mode;
+    }
+
+    /**
+     * Sets the subscription mode for CDMA phone to the given mode {@code mode}.
+     *
+     * @param mode CDMA subscription mode.
+     * @throws SecurityException if the caller does not have the permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     *
+     * @see #CDMA_SUBSCRIPTION_UNKNOWN
+     * @see #CDMA_SUBSCRIPTION_RUIM_SIM
+     * @see #CDMA_SUBSCRIPTION_NV
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void setCdmaSubscriptionMode(@CdmaSubscription int mode) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                boolean result = telephony.setCdmaSubscriptionMode(getSubId(), mode);
+                if (!result) throw new IllegalStateException("radio is unavailable.");
+            } else {
+                throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "Error calling ITelephony#setCdmaSubscriptionMode", ex);
+            ex.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index b054dfc..993e07a 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -110,10 +110,10 @@
     public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3;
 
     /**
-     * Indicates that data retry interval is not specified. Platform can determine when to
+     * Indicates that data retry duration is not specified. Platform can determine when to
      * perform data setup appropriately.
      */
-    public static final int RETRY_INTERVAL_UNDEFINED = -1;
+    public static final int RETRY_DURATION_UNDEFINED = -1;
 
     private final @DataFailureCause int mCause;
     private final long mSuggestedRetryTime;
@@ -236,12 +236,12 @@
     /**
      * @return The suggested data retry time in milliseconds.
      *
-     * @deprecated Use {@link #getRetryIntervalMillis()} instead.
+     * @deprecated Use {@link #getRetryDurationMillis()} instead.
      */
     @Deprecated
     public int getSuggestedRetryTime() {
         // To match the pre-deprecated getSuggestedRetryTime() behavior.
-        if (mSuggestedRetryTime == RETRY_INTERVAL_UNDEFINED) {
+        if (mSuggestedRetryTime == RETRY_DURATION_UNDEFINED) {
             return 0;
         } else if (mSuggestedRetryTime > Integer.MAX_VALUE) {
             return Integer.MAX_VALUE;
@@ -250,11 +250,11 @@
     }
 
     /**
-     * @return The network suggested data retry interval in milliseconds. {@code Long.MAX_VALUE}
-     * indicates data retry should not occur. {@link #RETRY_INTERVAL_UNDEFINED} indicates network
-     * did not suggest any retry interval.
+     * @return The network suggested data retry duration in milliseconds. {@code Long.MAX_VALUE}
+     * indicates data retry should not occur. {@link #RETRY_DURATION_UNDEFINED} indicates network
+     * did not suggest any retry duration.
      */
-    public long getRetryIntervalMillis() {
+    public long getRetryDurationMillis() {
         return mSuggestedRetryTime;
     }
 
@@ -472,7 +472,7 @@
     public static final class Builder {
         private @DataFailureCause int mCause;
 
-        private long mSuggestedRetryTime = RETRY_INTERVAL_UNDEFINED;
+        private long mSuggestedRetryTime = RETRY_DURATION_UNDEFINED;
 
         private int mId;
 
@@ -521,7 +521,7 @@
          * @param suggestedRetryTime The suggested data retry time in milliseconds.
          * @return The same instance of the builder.
          *
-         * @deprecated Use {@link #setRetryIntervalMillis(long)} instead.
+         * @deprecated Use {@link #setRetryDurationMillis(long)} instead.
          */
         @Deprecated
         public @NonNull Builder setSuggestedRetryTime(int suggestedRetryTime) {
@@ -530,13 +530,13 @@
         }
 
         /**
-         * Set the network suggested data retry interval.
+         * Set the network suggested data retry duration.
          *
-         * @param retryIntervalMillis The suggested data retry interval in milliseconds.
+         * @param retryDurationMillis The suggested data retry duration in milliseconds.
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setRetryIntervalMillis(long retryIntervalMillis) {
-            mSuggestedRetryTime = retryIntervalMillis;
+        public @NonNull Builder setRetryDurationMillis(long retryDurationMillis) {
+            mSuggestedRetryTime = retryDurationMillis;
             return this;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a38d5b6..51aa9cc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1798,6 +1798,14 @@
     boolean setCdmaRoamingMode(int subId, int mode);
 
     /**
+     * Gets the subscription mode for the CDMA phone with the subscription id {@code subId}.
+     *
+     * @param the subscription id.
+     * @return the subscription mode for CDMA phone.
+     */
+    int getCdmaSubscriptionMode(int subId);
+
+    /**
      * Sets the subscription mode for CDMA phone with the subscription {@code subId} to the given
      * subscription mode {@code mode}.
      *
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index ec47550..8444833 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util.test;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -140,6 +141,24 @@
         return this;
     }
 
+    /** Stages multiple APEXs within the host test jar onto the device. */
+    public SystemPreparer stageMultiplePackages(String[] resourcePaths, String[] packageNames)
+            throws DeviceNotAvailableException, IOException {
+        assertEquals(resourcePaths.length, packageNames.length);
+        final ITestDevice device = mDeviceProvider.getDevice();
+        final String[] adbCommandLine = new String[resourcePaths.length + 2];
+        adbCommandLine[0] = "install-multi-package";
+        adbCommandLine[1] = "--staged";
+        for (int i = 0; i < resourcePaths.length; i++) {
+            final File tmpFile = copyResourceToTemp(resourcePaths[i]);
+            adbCommandLine[i + 2] = tmpFile.getAbsolutePath();
+            mInstalledPackages.add(packageNames[i]);
+        }
+        final String output = device.executeAdbCommand(adbCommandLine);
+        assertTrue(output.contains("Success. Reboot device to apply staged session"));
+        return this;
+    }
+
     /** Sets the enable state of an overlay package. */
     public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
             throws DeviceNotAvailableException {
@@ -210,9 +229,27 @@
         return this;
     }
 
+    private static @Nullable String getFileExtension(@Nullable String path) {
+        if (path == null) {
+            return null;
+        }
+        final int lastDot = path.lastIndexOf('.');
+        if (lastDot >= 0) {
+            return path.substring(lastDot + 1);
+        } else {
+            return null;
+        }
+    }
+
     /** Copies a file within the host test jar to a temporary file on the host machine. */
     private File copyResourceToTemp(String resourcePath) throws IOException {
-        final File tempFile = mHostTempFolder.newFile();
+        final String ext = getFileExtension(resourcePath);
+        final File tempFile;
+        if (ext != null) {
+            tempFile = File.createTempFile("junit", "." + ext, mHostTempFolder.getRoot());
+        } else {
+            tempFile = mHostTempFolder.newFile();
+        }
         final ClassLoader classLoader = getClass().getClassLoader();
         try (InputStream assetIs = classLoader.getResourceAsStream(resourcePath);
              FileOutputStream assetOs = new FileOutputStream(tempFile)) {
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
index e482708..a0a5a29 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProvider.java
@@ -92,6 +92,14 @@
     }
 
     /**
+     * Creates a {@link org.junit.rules.TestRule} that makes sure {@link #clearSettingsProvider()}
+     * is triggered before and after each test.
+     */
+    public static FakeSettingsProviderRule rule() {
+        return new FakeSettingsProviderRule();
+    }
+
+    /**
      * This needs to be called before and after using the FakeSettingsProvider class.
      */
     public static void clearSettingsProvider() {
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java
new file mode 100644
index 0000000..c4e9545
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/internal/util/test/FakeSettingsProviderRule.java
@@ -0,0 +1,76 @@
+/*
+ * 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.internal.util.test;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * JUnit Rule helps keeping test {@link FakeSettingsProvider} clean.
+ *
+ * <p>It clears {@link FakeSettingsProvider} before and after each test. Example use:
+ * <pre class="code"><code class="java">
+ * public class ExampleTest {
+ *
+ *     &#064;Rule public FakeSettingsProviderRule rule = FakeSettingsProvider.rule();
+ *
+ *     &#064;Test
+ *     public void shouldDoSomething() {
+ *         ContextResolver cr = rule.mockContentResolver(mContext);
+ *         Settings.Global.putInt(cr, "my_setting_name", 1);
+ *         // Test code relying on my_setting_name value using cr
+ *     }
+ * }
+ * </code></pre>
+ *
+ * @see FakeSettingsProvider
+ */
+public final class FakeSettingsProviderRule implements TestRule {
+
+    /** Prevent initialization outside {@link FakeSettingsProvider}. */
+    FakeSettingsProviderRule() {
+    }
+
+    /**
+     * Creates a {@link MockContentResolver} that uses the {@link FakeSettingsProvider} as the
+     * {@link Settings#AUTHORITY} provider.
+     */
+    public MockContentResolver mockContentResolver(Context context) {
+        MockContentResolver contentResolver = new MockContentResolver(context);
+        contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        return contentResolver;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            public void evaluate() throws Throwable {
+                FakeSettingsProvider.clearSettingsProvider();
+                try {
+                    base.evaluate();
+                } finally {
+                    FakeSettingsProvider.clearSettingsProvider();
+                }
+            }
+        };
+    }
+}
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
index fde3a6a..8c51510 100644
--- a/wifi/TEST_MAPPING
+++ b/wifi/TEST_MAPPING
@@ -8,5 +8,18 @@
         }
       ]
     }
+  ],
+  "mainline-presubmit": [
+    {
+      "name": "FrameworksWifiApiTests[com.google.android.wifi.apex]"
+    },
+    {
+      "name": "CtsWifiTestCases[com.google.android.wifi.apex]",
+      "options": [
+        {
+          "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+        }
+      ]
+    }
   ]
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f34890e..e1e9757 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2736,17 +2736,18 @@
     }
 
     /**
-     * Get a key for this WifiConfig to generate Persist random Mac Address.
+     * Get a unique key which represent this Wi-Fi network. If two profiles are for
+     * the same Wi-Fi network, but from different provider, they would have the same key.
      * @hide
      */
-    public String getMacRandomKey() {
+    public String getNetworkKey() {
         // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
         // able to match internally.
         if (mPasspointUniqueId != null) {
             return mPasspointUniqueId;
         }
 
-        String key = getSsidAndSecurityTypeString();
+        String key = SSID + getDefaultSecurityType();
         if (!shared) {
             key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
         }
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index b710a14..7272e14 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -45,7 +45,7 @@
     ],
 
     test_suites: [
-        "device-tests",
+        "general-tests",
         "mts",
     ],
 
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 34e2e3a..2cdaddb 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -20,6 +20,8 @@
 
     <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="FrameworksWifiApiTests" />
+    <option name="config-descriptor:metadata" key="mainline-param"
+            value="com.google.android.wifi.apex" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.wifi.test" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 337ad92..c881324 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -426,11 +426,11 @@
     }
 
     /**
-     * Verifies that getMacRandomKey returns the correct String for networks of
+     * Verifies that getNetworkKey returns the correct String for networks of
      * various different security types, the result should be stable.
      */
     @Test
-    public void testGetMacRandomKeyString() {
+    public void testGetNetworkKeyString() {
         WifiConfiguration config = new WifiConfiguration();
         final String mSsid = "TestAP";
         config.SSID = mSsid;
@@ -438,23 +438,23 @@
         // Test various combinations
         config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK],
-                config.getMacRandomKey());
+                config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP],
-                config.getMacRandomKey());
+                config.getNetworkKey());
 
         config.wepKeys[0] = "TestWep";
         config.allowedKeyManagement.clear();
-        assertEquals(mSsid + "WEP", config.getMacRandomKey());
+        assertEquals(mSsid + "WEP", config.getNetworkKey());
 
         // set WEP key and give a valid index.
         config.wepKeys[0] = null;
         config.wepKeys[2] = "TestWep";
         config.wepTxKeyIndex = 2;
         config.allowedKeyManagement.clear();
-        assertEquals(mSsid + "WEP", config.getMacRandomKey());
+        assertEquals(mSsid + "WEP", config.getNetworkKey());
 
         // set WEP key but does not give a valid index.
         config.wepKeys[0] = null;
@@ -462,40 +462,40 @@
         config.wepTxKeyIndex = 0;
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.OWE);
-        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
 
         config.wepKeys[0] = null;
         config.wepTxKeyIndex = 0;
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.OWE);
-        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.SAE);
-        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getMacRandomKey());
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SUITE_B_192],
-                config.getMacRandomKey());
+                config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.NONE);
-        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getMacRandomKey());
+        assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
-                config.getMacRandomKey());
+                config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
         assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
-                config.getMacRandomKey());
+                config.getNetworkKey());
 
         config.allowedKeyManagement.clear();
         config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
-        assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getMacRandomKey());
+        assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getNetworkKey());
     }
 
     /**